基于OAtuth2的新浪微博Java爬虫

申明:本文代码不幸遗失,如果对您造成不便,请谅解,谢谢

OAUTH协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式不同之处是OAUTH的授权不会使第三方触及到用户的帐号信息(如用户名与密码),即第三方无需使用用户的用户名与密码就可以申请获得该用户资源的授权,因此OAUTH是安全的。oAuth是Open Authorization的简写。

其实多数尝试动手写新浪微博爬虫的童鞋都知道,新浪微博虽然为用户提供了API调用的接口。但是依然是存在调用频率限制、API设计不完整等诸多问题。因此在某些需要大规模或者详细数据获取的一些研究我们还是得自己动手解析新浪微博的网页。

代码结构图

说明

请先填写相关配置:在Config.properties里
client_ID :appkey                           
client_SERCRET :app_secret
redirect_URI : 回调地址
将存储文件中的文件拷贝到D盘
申请微博的开发者权限
http://open.weibo.com/development
下载Java的SDK,然后调用相关的接口,例如
http://open.weibo.com/wiki/2/friendships/followers
返回结果是JSON
运行主类GetFriendsData.java

依赖jar包

链接:http://pan.baidu.com/s/1qW3iI4G 密码:wvdz

存储文件

链接:http://pan.baidu.com/s/1jG4aTlc 密码:eoxa

配置文件

config.properties

client_ID = 2299723665    
client_SERCRET = af784b4e0fc05c7e2ff7bc9c7453c3f6
redirect_URI = http://www.baidu.com
baseURL=https://api.weibo.com/2/
accessTokenURL=https://api.weibo.com/oauth2/access_token
authorizeURL=https://api.weibo.com/oauth2/authorize
rmURL=https\://rm.api.weibo.com/2/

log4j.properties

  log4j.rootLogger=debug, stdout, R
  log4j.appender.stdout=org.apache.log4j.ConsoleAppender
  log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

  log4j.logger.org.apache.commons.httpclient=info
  log4j.logger.httpclient.wire.content=info
  log4j.logger.httpclient.wire.header=info

  # Pattern to output the caller's file name and line number.
  log4j.appender.stdout.layout.ConversionPattern=%-4r %-5p [%d{yyyy-MM-dd HH:mm:ss}]  %m%n

  log4j.appender.R=org.apache.log4j.RollingFileAppender
  log4j.appender.R.File=weibo.log
  log4j.appender.R.MaxFileSize= 100KB

  # Keep one backup file
  log4j.appender.R.MaxBackupIndex=1

  log4j.appender.R.layout=org.apache.log4j.PatternLayout
  log4j.appender.R.layout.ConversionPattern=%-4r %-5p [%d{yyyy-MM-dd HH\:mm\:ss}]  %m%n

getData包

GetFriendsData.java

package getData;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.util.Iterator;
import java.util.List;

import weibo4j.Friendships;
import weibo4j.model.User;
import weibo4j.model.UserWapper;
import weibo4j.model.WeiboException;

public class GetFriendsData {

    private BufferedWriter bw;
    private BufferedReader br;
    private String userID;
    private UserWapper userWapper;
    private Friendships friends;
    private String token;
    private List<User> users;

    public void getDataFromSina() throws IOException {
        br = new BufferedReader(new InputStreamReader(new FileInputStream(
                "D:\\sinaData.txt"), "gbk"));
        String line = null;
        try {
            line = br.readLine();
            if (line != null) {
                int begin = line.indexOf("=");
                userID = line.substring(begin, begin + 10);
                friends = new Friendships();
                friends.client.setToken(token);
                // 获取用户关注的用户列表

                userWapper = friends.getFollowersById(userID);

                users = userWapper.getUsers();
                File file = new File("D:\\users.txt");
                if (!file.exists()) {
                    bw = new BufferedWriter(new OutputStreamWriter(
                            new FileOutputStream("D:\\users.txt"), "gbk"));
                } else

                {
                    bw = new BufferedWriter(new OutputStreamWriter(
                            new FileOutputStream("D:\\users.txt", true), "gbk"));
                }
                Iterator<User> iterator = users.iterator();
                User user = null;
                while (iterator.hasNext()) {
                    user = (User) iterator.next();
                    bw.write(user.toString() + "\n");
                    bw.flush();

                }
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (WeiboException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            bw.close();
        }
    }

    /**
     * @param args
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub

        Friendships friends = new Friendships();
        String userID = "2034465497";
        String token = "2.00d66gNC0WEQHS4a88a85c7903wynB";
        friends.client.setToken(token);
        UserWapper userWapper = null;
        List<User> users = null;
        BufferedWriter bw = null;
        try {
            // 获取用户关注的用户列表
            userWapper = friends.getFollowersById(userID);
            users = userWapper.getUsers();

            bw = new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream("D:\\users.txt"), "gbk"));
            Iterator<User> iterator = users.iterator();
            User user = null;
            while (iterator.hasNext()) {
                user = (User) iterator.next();
                bw.write(user.toString() + "\n");
                bw.flush();

            }
        } catch (WeiboException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.out.println(e);
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            bw.close();
        }

    }

}

graph包

GraphGenerate.java

package graph;

import java.util.LinkedList;
import java.util.HashMap;
import java.util.Set;
import java.util.HashSet;
import java.util.Iterator;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;

import weibo4j.Friendships;
import weibo4j.model.WeiboException;


public class GraphGenerate {

    private String uid; // My id for application in sina
    private String access_Token; // My access token for application in sina
    private Friendships fm;

    private BufferedWriter bw;
    private BufferedReader br;

    private HashMap<String, LinkedList<String>> table; // Define an adjacency
                                                        // list

    private int count; // Authorize count (75/h)

    public GraphGenerate() { // Constructor

        try {

            br = new BufferedReader(new InputStreamReader(new FileInputStream(
                    "D:\\liu\\AccessToken.txt")));

            access_Token = br.readLine(); // Initialize
            uid = br.readLine();

            fm = new Friendships();

            table = new HashMap<String, LinkedList<String>>();

            br = new BufferedReader(new InputStreamReader(new FileInputStream(
                    "D:\\liu\\GraphGenerateId.txt")));

            bw = new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream("D:\\liu\\TmpGraphGenerateId.txt")));

            count = 10;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private String[] getIds(String friendId) { // Get friends' ids of the
                                                // friendId

        fm.client.setToken(access_Token);
        String[] ids = null;

        try {
            ids = fm.getFriendsIdsByUid(friendId); // Sina interface
        } catch (WeiboException e) {
            e.printStackTrace();
        }
        return ids;
    }

    private LinkedList<String> getList(String[] ids) { // Generate a list for
                                                        // ids

        LinkedList<String> list = new LinkedList<String>();

        for (int i = 0; i < ids.length; i++) {
            list.add(ids[i]);
        }

        return list;
    }

    private void generateGraph() { // Invocated when the information of graph is
                                    // none

        table.put(uid, getList(getIds(uid))); // Put my friends' ids to table
                                                // for the first time

        adjustTable(); // Generate more graph information to table
    }

    private void adjustTable() { // Generate more graph information to table

        HashMap<String, LinkedList<String>> tmpTable = new HashMap<String, LinkedList<String>>(); // Extended
                                                                                                    // node
                                                                                                    // should
                                                                                                    // be
                                                                                                    // putted
                                                                                                    // in
                                                                                                    // this
                                                                                                    // table

        Set<String> keyset = table.keySet();

        LinkedList<String> list;

        Iterator<String> itkey = keyset.iterator();

        Iterator<String> itlist;

        String keyid;

        String id;

        while (itkey.hasNext()) { // The next map key

            keyid = itkey.next();

            list = table.get(keyid);

            itlist = list.iterator();

            while (itlist.hasNext()) { // The next list's element

                id = itlist.next();

                if (!table.containsKey(id)) {

                    tmpTable.put(id, getList(getIds(id)));

                    this.count--;
                }

                if (this.count == 0) {
                    break;
                }
            }

            if (this.count == 0) {
                break;
            }
        }

        itkey = tmpTable.keySet().iterator();

        while (itkey.hasNext()) {

            id = itkey.next();

            table.put(id, tmpTable.get(id));

        }
    }

    private void serializeTable() { // Put the adjacency to the disk

        Set<String> keyset = table.keySet();

        Iterator<String> itkey = keyset.iterator();

        Iterator<String> itlist;

        LinkedList<String> list;

        String id;

        try {

            while (itkey.hasNext()) { // The key set

                id = itkey.next();

                bw.write("\n" + id + "\t:\t");

                list = table.get(id);

                itlist = list.iterator();

                while (itlist.hasNext()) { // The list

                    bw.write(itlist.next() + "\t");

                }

                bw.write("\n");
            }

            bw.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private boolean shouldRemove(LinkedList<String> ids, Set<String> reIds) { // If
                                                                                // the
                                                                                // node
                                                                                // we
                                                                                // have
                                                                                // search
                                                                                // in
                                                                                // the
                                                                                // file
                                                                                // Should
                                                                                // not
                                                                                // read
                                                                                // to
                                                                                // table
        Iterator<String> it = ids.iterator();

        while (it.hasNext()) {
            if (!reIds.contains(it.next())) {
                return false; // Read the node
            }
        }

        return true; // Discard the list
    }

    private void deSerializeTable() { // Read the adjacency from the file of
                                        // GraphGenerateId
                                        // The memory has only 75 item of
                                        // adjacency table
        int amount = 10; // Assume the list read at least have a node that needs
                            // to invocate the interface of sina
        String str;
        String[] strs;

        String head = null;

        LinkedList<String> list = null;

        Set<String> reIds = new HashSet<String>(); // Redundante ids in map key

        try {

            while ((str = br.readLine()) != null) { // Initialize the reIds

                if (str.contains(":")) {

                    strs = str.split("\t");

                    reIds.add(strs[0]);

                }
            }

            br = new BufferedReader(new InputStreamReader(new FileInputStream(
                    "D:\\liu\\GraphGenerateId.txt")));

            while ((str = br.readLine()) != null) {

                if (str.equals("")) {
                    continue;
                }

                if (str.contains(":")) { // A list head

                    if (list != null) {

                        if (!shouldRemove(list, reIds)) {

                            table.put(head, list);

                            amount--;

                        }

                        if (amount == 0) { // Have enough list in table
                            break;
                        }
                    }

                    strs = str.split("\t");

                    head = strs[0];

                    list = new LinkedList<String>();

                    for (int i = 2; i < strs.length; i++) {
                        list.add(strs[i]);
                    }

                } else {

                    strs = str.split("\t");

                    for (int i = 0; i < strs.length; i++) {
                        list.add(strs[i]);
                    }
                }
            }

            if (amount == 0) {
                return;
            }

            if (!shouldRemove(list, reIds)) { // The last list

                table.put(head, list);

            }

        } catch (FileNotFoundException e1) {
            e1.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void releaseResourse() { // Release the related stream

        try {
            br.close();
            bw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void start() { // The main function

        try {

            if (br.readLine() == null) { // No information of graph on the disk
                generateGraph();
            } else {
                deSerializeTable(); // Read file(Only 240 id_key-id_list)
                adjustTable();
            }

            serializeTable();

            releaseResourse();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

GraphGenerateDriver.java

package graph;



public class GraphGenerateDriver {

    public static void main(String[] args) {

        GraphGenerate gg = new GraphGenerate();

        MergeGraph mg = new MergeGraph();

        gg.start(); // Step onee

        mg.start(); // Step two

    }
}

MergeGraph.java

package graph;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.FileInputStream;
import java.io.BufferedWriter;
import java.io.OutputStreamWriter;
import java.io.FileOutputStream;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;

import weibo4j.Friendships;
import weibo4j.Users;
import weibo4j.model.User;
import weibo4j.model.UserWapper;
import weibo4j.model.WeiboException;



public class MergeGraph { // Merge the file of TmpGenerateGraphId to the file of
                            // GenerateGraphId
                            // Need to remove redundancy item
    private BufferedReader br;
    private BufferedWriter bw1;
    private BufferedWriter bw2;
    private Set<String> set; // The ids existed in the file of GraphGenerateId
    private Map<String, LinkedList<String>> table; // The adjacency in file of
                                                    // TmpGraphGenerateId

    private String access_Token;

    private Friendships fm;
    private UserWapper users;
    private User user;
    private Users um;

    public MergeGraph() { // Construct

        try {
            br = new BufferedReader(new InputStreamReader(new FileInputStream(
                    "D:\\liu\\AccessToken.txt")));
            access_Token = br.readLine();
        } catch (IOException e) {
            e.printStackTrace();
        }

        set = new HashSet<String>();
        table = new HashMap<String, LinkedList<String>>();
        fm = new Friendships();
        fm.client.setToken(access_Token);
        um = new Users();
        um.client.setToken(access_Token);

        br = null;
    }

    private class ConstantString { // Format Token

        private static final String NODE_USER = "�����û���\t";

        private static final String OUT_DEGREE_USER = "����û���\n";

        private static final String SEPARATER1 = "--------------------------------------------------------------------\n";

        private static final String SEPARATER2 = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
                + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n";
    }

    private void deSerializeTable() { // Read the adjacency from the file of
                                        // TmpGraphGeneratedId

        String str;
        String[] strs;

        try {

            br = new BufferedReader(new InputStreamReader(new FileInputStream(
                    "D:\\liu\\TmpGraphGenerateId.txt")));

            String head = null;

            LinkedList<String> list = null;

            while ((str = br.readLine()) != null) {

                if (str.equals("")) {
                    continue;
                }

                if (str.contains(":")) { // A list head

                    if (list != null) {

                        table.put(head, list);

                    }

                    strs = str.split("\t");

                    head = strs[0];

                    list = new LinkedList<String>();

                    for (int i = 2; i < strs.length; i++) {
                        list.add(strs[i]);
                    }

                } else {

                    strs = str.split("\t");

                    for (int i = 0; i < strs.length; i++) {
                        list.add(strs[i]);
                    }
                }
            }

            table.put(head, list); // The last list

        } catch (FileNotFoundException e1) {
            e1.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void serializeTable() { // Merge the graph information in the file
                                    // of TmpGraphGenerateId
                                    // to the file of GraphGeneratedId(need to
                                    // remove redundancy item)
                                    // At the same time, generate detail
                                    // information to the file of
                                    // GraphGenerateDetailInfo
        String str;
        String[] strs;

        try {
            br = new BufferedReader(new InputStreamReader(new FileInputStream(
                    "D:\\liu\\GraphGenerateId.txt")));

            while ((str = br.readLine()) != null) { // Initial set

                if (str.contains(":")) {
                    strs = str.split("\t");
                    set.add(strs[0]);
                }
            }

            Iterator<String> itkey = table.keySet().iterator();

            bw1 = new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream("D:\\liu\\GraphGenerateId.txt", true)));

            bw2 = new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream(
                            "D:\\liu\\GraphGenerateDetailInfo.txt", true)));

            LinkedList<String> list;

            Iterator<String> itlist;

            while (itkey.hasNext()) { // The key set

                str = itkey.next();

                if (!set.contains(str)) {

                    bw1.write("\n" + str + "\t:\t");

                    bw2.write(ConstantString.NODE_USER + str + "\n\n");

                    user = um.showUserById(str);

                    bw2.write(user.toString() + "\n\n"); // The detail
                                                            // information of
                                                            // user node

                    bw2.write(ConstantString.SEPARATER1 + "\n");

                    bw2.write(ConstantString.OUT_DEGREE_USER + "\n");

                    users = fm.getFriendsByID(str);

                    for (User u : users.getUsers()) {
                        bw2.write(u.toString() + "\n\n"); // The detail
                                                            // information of
                                                            // out degree user
                    }

                    bw2.write(ConstantString.SEPARATER2 + "\n");

                    list = table.get(str);

                    itlist = list.iterator();

                    while (itlist.hasNext()) { // The list

                        bw1.write(itlist.next() + "\t");

                    }

                    bw1.write("\n");
                }

            }

            bw1.flush();
            bw2.flush();

        } catch (IOException e) {
            e.printStackTrace();
        } catch (WeiboException e) {
            e.printStackTrace();
        }
    }

    private void releaseResource() {
        try {
            br.close();
            bw1.close();
            bw2.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void start() {

        deSerializeTable();

        serializeTable();

        releaseResource();

    }

}

IO包

FileIOOperation.java

package IO;

import java.io.FileWriter;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.io.Reader;

public class FileIOOperation {
    /**
     * 以字节为单位读取文件,常用于读二进制文件,如图片、声音、影像等文件。
     * 
     * @param fileName
     *            文件的名
     */
    public static void readFileByBytes(String fileName) {
        File file = new File(fileName);
        InputStream in = null;
        try {
            System.out.println("以字节为单位读取文件内容,一次读一个字节:");
            // 一次读一个字节
            in = new FileInputStream(file);
            int tempbyte;
            while ((tempbyte = in.read()) != -1) {
                System.out.write(tempbyte);
            }
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
            return;
        }
        try {
            System.out.println("以字节为单位读取文件内容,一次读多个字节:");
            // 一次读多个字节
            byte[] tempbytes = new byte[100];
            int byteread = 0;
            in = new FileInputStream(fileName);
            FileIOOperation.showAvailableBytes(in);
            // 读入多个字节到字节数组中,byteread为一次读入的字节数
            while ((byteread = in.read(tempbytes)) != -1) {
                System.out.write(tempbytes, 0, byteread);
            }
        } catch (Exception e1) {
            e1.printStackTrace();
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e1) {
                }
            }
        }
    }

    /**
     * 以字符为单位读取文件,常用于读文本,数字等类型的文件
     * 
     * @param fileName
     *            文件名
     */
    public static void readFileByChars(String fileName) {
        File file = new File(fileName);
        Reader reader = null;
        try {
            System.out.println("以字符为单位读取文件内容,一次读一个字节:");
            // 一次读一个字符
            reader = new InputStreamReader(new FileInputStream(file));
            int tempchar;
            while ((tempchar = reader.read()) != -1) {
                // 对于windows下,这两个字符在一起时,表示一个换行。
                // 但如果这两个字符分开显示时,会换两次行。
                // 因此,屏蔽掉,或者屏蔽。否则,将会多出很多空行。
                if (((char) tempchar) != ' ') {
                    System.out.print((char) tempchar);
                }
            }
            reader.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            System.out.println("以字符为单位读取文件内容,一次读多个字节:");
            // 一次读多个字符
            char[] tempchars = new char[30];
            int charread = 0;
            reader = new InputStreamReader(new FileInputStream(fileName));
            // 读入多个字符到字符数组中,charread为一次读取字符数
            while ((charread = reader.read(tempchars)) != -1) {
                // 同样屏蔽掉不显示
                if ((charread == tempchars.length)
                        && (tempchars[tempchars.length - 1] != ' ')) {
                    System.out.print(tempchars);
                } else {
                    for (int i = 0; i < charread; i++) {
                        if (tempchars[i] == ' ') {
                            continue;
                        } else {
                            System.out.print(tempchars[i]);
                        }
                    }
                }
            }

        } catch (Exception e1) {
            e1.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e1) {
                }
            }
        }
    }

    /**
     * 以行为单位读取文件,常用于读面向行的格式化文件
     * 
     * @param fileName
     *            文件名
     */
    public static void readFileByLines(String fileName) {
        File file = new File(fileName);
        BufferedReader reader = null;
        try {
            System.out.println("以行为单位读取文件内容,一次读一整行:");
            reader = new BufferedReader(new FileReader(file));
            String tempString = null;
            int line = 1;
            // 一次读入一行,直到读入null为文件结束
            while ((tempString = reader.readLine()) != null) {
                // 显示行号
                System.out.println("line " + line + ": " + tempString);
                line++;
            }
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e1) {
                }
            }
        }
    }

    /**
     * 随机读取文件内容
     * 
     * @param fileName
     *            文件名
     */
    public static void readFileByRandomAccess(String fileName) {
        RandomAccessFile randomFile = null;
        try {
            System.out.println("随机读取一段文件内容:");
            // 打开一个随机访问文件流,按只读方式
            randomFile = new RandomAccessFile(fileName, "r");
            // 文件长度,字节数
            long fileLength = randomFile.length();
            // 读文件的起始位置
            int beginIndex = (fileLength > 4) ? 4 : 0;
            // 将读文件的开始位置移到beginIndex位置。
            randomFile.seek(beginIndex);
            byte[] bytes = new byte[10];
            int byteread = 0;
            // 一次读10个字节,如果文件内容不足10个字节,则读剩下的字节。
            // 将一次读取的字节数赋给byteread
            while ((byteread = randomFile.read(bytes)) != -1) {
                System.out.write(bytes, 0, byteread);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (randomFile != null) {
                try {
                    randomFile.close();
                } catch (IOException e1) {
                }
            }
        }
    }

    /**
     * 显示输入流中还剩的字节数
     * 
     * @param in
     */
    private static void showAvailableBytes(InputStream in) {
        try {
            System.out.println("当前字节输入流中的字节数为:" + in.available());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }



    /**
     * A方法追加文件:使用RandomAccessFile
     * 
     * @param fileName
     *            文件
     * @param content
     *            追加的内容
     */
    public static void appendMethodA(String fileName, String content) {
        try {
            // 打开一个随机访问文件流,按读写方式
            RandomAccessFile randomFile = new RandomAccessFile(fileName, "rw");
            // 文件长度,字节数
            long fileLength = randomFile.length();
            // 将写文件指针移到文件尾。
            randomFile.seek(fileLength);
            randomFile.writeBytes(content);
            randomFile.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * B方法追加文件:使用FileWriter
     * 
     * @param fileName
     * @param content
     */
    public static void appendMethodB(String fileName, String content) {
        try {
            // 打开一个写文件器,构造函数中的第二个参数true表示以追加形式写文件
            FileWriter writer = new FileWriter(fileName, true);
            writer.write(content);
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

weibo4j包

Friendships.java

package weibo4j;

import weibo4j.model.Paging;
import weibo4j.model.PostParameter;
import weibo4j.model.User;
import weibo4j.model.UserWapper;
import weibo4j.model.WeiboException;
import weibo4j.org.json.JSONArray;
import weibo4j.util.WeiboConfig;

public class Friendships extends Weibo {
    /**
     * 
     */
    private static final long serialVersionUID = 3603512821159421447L;

    /*----------------------------关系接口----------------------------------------*/
    /**
     * 获取用户的关注列表
     * 
     * @return list of the user's follow
     * @throws WeiboException
     *             when Weibo service or network is unavailable
     * @version weibo4j-V2 1.0.0
     * @see <a
     *      href="http://open.weibo.com/wiki/2/friendships/friends">friendships/friends</a>
     * @since JDK 1.5
     */
    public UserWapper getFriendsByID(String id) throws WeiboException {
        return User.constructWapperUsers(client.get(
                WeiboConfig.getValue("baseURL") + "friendships/friends.json",
                new PostParameter[] { new PostParameter("uid", id) }));
    }

    /**
     * 获取用户的关注列表
     * 
     * @return list of the user's follow
     * @throws WeiboException
     *             when Weibo service or network is unavailable
     * @version weibo4j-V2 1.0.0
     * @see <a
     *      href="http://open.weibo.com/wiki/2/friendships/friends">friendships/friends</a>
     * @since JDK 1.5
     */
    public UserWapper getFriendsByScreenName(String screen_name)
            throws WeiboException {
        return User.constructWapperUsers(client.get(
                WeiboConfig.getValue("baseURL") + "friendships/friends.json",
                new PostParameter[] { new PostParameter("screen_name",
                        screen_name) }));
    }

    /**
     * 获取两个用户之间的共同关注人列表
     * 
     * @param uid
     *            需要获取共同关注关系的用户UID
     * @return list of the user's follow
     * @throws WeiboException
     *             when Weibo service or network is unavailable
     * @version weibo4j-V2 1.0.0
     * @see <a
     *      href="http://open.weibo.com/wiki/2/friendships/friends/in_common">friendships/friends/in_common</a>
     * @since JDK 1.5
     */
    public UserWapper getFriendsInCommon(String uid) throws WeiboException {
        return User.constructWapperUsers(client.get(
                WeiboConfig.getValue("baseURL")
                        + "friendships/friends/in_common.json",
                new PostParameter[] { new PostParameter("uid", uid) }));
    }

    /**
     * 获取两个用户之间的共同关注人列表
     * 
     * @param uid
     *            需要获取共同关注关系的用户UID
     * @param suid
     *            需要获取共同关注关系的用户UID,默认为当前登录用户
     * @param count
     *            单页返回的记录条数,默认为50
     * @param page
     *            返回结果的页码,默认为1
     * @return list of the user's follow
     * @throws WeiboException
     *             when Weibo service or network is unavailable
     * @version weibo4j-V2 1.0.0
     * @see <a
     *      href="http://open.weibo.com/wiki/2/friendships/friends/in_common">friendships/friends/in_common</a>
     * @since JDK 1.5
     */
    public UserWapper getFriendsInCommon(String uid, String suid, Paging page)
            throws WeiboException {
        return User.constructWapperUsers(client.get(
                WeiboConfig.getValue("baseURL")
                        + "friendships/friends/in_common.json",
                new PostParameter[] { new PostParameter("uid", uid),
                        new PostParameter("suid", suid) }, page));
    }

    /**
     * 获取用户的双向关注列表,即互粉列表
     * 
     * @param uid
     *            需要获取双向关注列表的用户UID
     * @return list of the user
     * @throws WeiboException
     *             when Weibo service or network is unavailable
     * @version weibo4j-V2 1.0.0
     * @see <a
     *      href="http://open.weibo.com/wiki/2/friendships/friends/bilateral">friendships/friends/bilateral</a>
     * @since JDK 1.5
     */
    public UserWapper getFriendsBilateral(String uid) throws WeiboException {
        return User.constructWapperUsers(client.get(
                WeiboConfig.getValue("baseURL")
                        + "friendships/friends/bilateral.json",
                new PostParameter[] { new PostParameter("uid", uid) }));
    }

    /**
     * 获取用户的双向关注列表,即互粉列表
     * 
     * @param uid
     *            需要获取双向关注列表的用户UID
     * @param count
     *            单页返回的记录条数,默认为50。
     * @param page
     *            返回结果的页码,默认为1。
     * @param sort
     *            排序类型,0:按关注时间最近排序,默认为0。
     * @return list of the user
     * @throws WeiboException
     *             when Weibo service or network is unavailable
     * @version weibo4j-V2 1.0.0
     * @return
     * @see <a
     *      href="http://open.weibo.com/wiki/2/friendships/friends/bilateral">friendships/friends/bilateral</a>
     * @since JDK 1.5
     */
    public UserWapper getFriendsBilateral(String uid, Integer sort, Paging page)
            throws WeiboException {
        return User.constructWapperUsers(client.get(
                WeiboConfig.getValue("baseURL")
                        + "friendships/friends/bilateral.json",
                new PostParameter[] { new PostParameter("uid", uid),
                        new PostParameter("sort", sort.toString()) }, page));
    }

    /**
     * 获取用户双向关注的用户ID列表,即互粉UID列表
     * 
     * @param uid
     *            需要获取双向关注列表的用户UID
     * @return ids
     * @throws WeiboException
     *             when Weibo service or network is unavailable
     * @version weibo4j-V2 1.0.0
     * @see <a
     *      href="http://open.weibo.com/wiki/2/friendships/friends/bilateral/ids">friendships/friends/bilateral/ids</a>
     * @since JDK 1.5
     */
    public String[] getFriendsBilateralIds(String uid) throws WeiboException {
        return User.constructIds(client.get(WeiboConfig.getValue("baseURL")
                + "friendships/friends/bilateral/ids.json",
                new PostParameter[] { new PostParameter("uid", uid) }));
    }

    /**
     * 获取用户双向关注的用户ID列表,即互粉UID列表
     * 
     * @param uid
     *            需要获取双向关注列表的用户UID
     * @param count
     *            单页返回的记录条数,默认为50。
     * @param page
     *            返回结果的页码,默认为1。
     * @param sort
     *            排序类型,0:按关注时间最近排序,默认为0。
     * @return ids
     * @throws WeiboException
     *             when Weibo service or network is unavailable
     * @version weibo4j-V2 1.0.0
     * @see <a
     *      href="http://open.weibo.com/wiki/2/friendships/friends/bilateral/ids">friendships/friends/bilateral/ids</a>
     * @since JDK 1.5
     */
    public String[] getFriendsBilateralIds(String uid, Integer sort, Paging page)
            throws WeiboException {
        return User.constructIds(client.get(WeiboConfig.getValue("baseURL")
                + "friendships/friends/bilateral/ids.json",
                new PostParameter[] { new PostParameter("uid", uid),
                        new PostParameter("sort", sort.toString()) }, page));
    }

    /**
     * 获取用户关注的用户UID列表
     * 
     * @param uid
     *            需要查询的用户UID
     * @return ids
     * @throws WeiboException
     *             when Weibo service or network is unavailable
     * @version weibo4j-V2 1.0.0
     * @see <a
     *      href="http://open.weibo.com/wiki/2/friendships/friends/ids">friendships/friends/ids</a>
     * @since JDK 1.5
     */
    public String[] getFriendsIdsByUid(String uid) throws WeiboException {
        return User.constructIds(client.get(WeiboConfig.getValue("baseURL")
                + "friendships/friends/ids.json",
                new PostParameter[] { new PostParameter("uid", uid) }));
    }

    /**
     * 获取用户关注的用户UID列表
     * 
     * @param uid
     *            需要查询的用户UID
     * @return ids
     * @throws WeiboException
     *             when Weibo service or network is unavailable
     * @version weibo4j-V2 1.0.0
     * @see <a
     *      href="http://open.weibo.com/wiki/2/friendships/friends/ids">friendships/friends/ids</a>
     * @since JDK 1.5
     */
    public String[] getFriendsIdsByName(String screen_name)
            throws WeiboException {
        return User.constructIds(client.get(WeiboConfig.getValue("baseURL")
                + "friendships/friends/ids.json",
                new PostParameter[] { new PostParameter("screen_name",
                        screen_name) }));
    }

    /**
     * 获取用户关注的用户UID列表
     * 
     * @param uid
     *            需要查询的用户UID
     * @param count
     *            单页返回的记录条数,默认为500,最大不超过5000
     * @param cursor
     *            返回结果的游标,下一页用返回值里的next_cursor,上一页用previous_cursor,默认为0
     * @return ids
     * @throws WeiboException
     *             when Weibo service or network is unavailable
     * @version weibo4j-V2 1.0.0
     * @see <a
     *      href="http://open.weibo.com/wiki/2/friendships/friends/ids">friendships/friends/ids</a>
     * @since JDK 1.5
     */
    public String[] getFriendsIdsByUid(String uid, Integer count, Integer cursor)
            throws WeiboException {
        return User.constructIds(client.get(WeiboConfig.getValue("baseURL")
                + "friendships/friends/ids.json",
                new PostParameter[] { new PostParameter("uid", uid),
                        new PostParameter("count", count.toString()),
                        new PostParameter("cursor", cursor.toString()) }));
    }

    /**
     * 获取用户关注的用户UID列表
     * 
     * @param screen_name
     *            需要查询的用户昵称
     * @param count
     *            单页返回的记录条数,默认为500,最大不超过5000
     * @param cursor
     *            返回结果的游标,下一页用返回值里的next_cursor,上一页用previous_cursor,默认为0
     * @return ids
     * @throws WeiboException
     *             when Weibo service or network is unavailable
     * @version weibo4j-V2 1.0.0
     * @see <a
     *      href="http://open.weibo.com/wiki/2/friendships/friends/ids">friendships/friends/ids</a>
     * @since JDK 1.5
     */
    public String[] getFriendsIdsByName(String screen_name, Integer count,
            Integer cursor) throws WeiboException {
        return User.constructIds(client.get(WeiboConfig.getValue("baseURL")
                + "friendships/friends/ids.json", new PostParameter[] {
                new PostParameter("screen_name", screen_name),
                new PostParameter("count", count.toString()),
                new PostParameter("cursor", cursor.toString()) }));
    }

    /**
     * 批量获取当前登录用户的关注人的备注信息
     * 
     * @param uids
     *            需要获取备注的用户UID,用半角逗号分隔,最多不超过50个
     * @return list of user's remark
     * @throws WeiboException
     *             when Weibo service or network is unavailable
     * @version weibo4j-V2 1.0.0
     * @see <a
     *      href="http://open.weibo.com/wiki/2/friendships/friends/remark_batch">friendships/friends/remark_batch</a>
     * @since JDK 1.5
     */
    public JSONArray getRemark(String uids) throws WeiboException {
        return client.get(
                WeiboConfig.getValue("baseURL")
                        + "friendships/friends/remark_batch.json",
                new PostParameter[] { new PostParameter("uids", uids) })
                .asJSONArray();
    }

    /**
     * 获取用户的粉丝列表
     * 
     * @param screen_name
     *            需要查询的用户昵称
     * @return list of users
     * @throws WeiboException
     *             when Weibo service or network is unavailable
     * @version weibo4j-V2 1.0.0
     * @see <a
     *      href="http://open.weibo.com/wiki/2/friendships/followers">friendships/followers</a>
     * @since JDK 1.5
     */
    public UserWapper getFollowersByName(String screen_name)
            throws WeiboException {
        return User.constructWapperUsers(client.get(
                WeiboConfig.getValue("baseURL") + "friendships/followers.json",
                new PostParameter[] { new PostParameter("screen_name",
                        screen_name) }));
    }

    /**
     * 获取用户的粉丝列表
     * 
     * @param screen_name
     *            需要查询的用户昵称
     * @param count
     *            单页返回的记录条数,默认为500,最大不超过5000
     * @param cursor
     *            返回结果的游标,下一页用返回值里的next_cursor,上一页用previous_cursor,默认为0
     * @return list of users
     * @throws WeiboException
     *             when Weibo service or network is unavailable
     * @version weibo4j-V2 1.0.0
     * @see <a
     *      href="http://open.weibo.com/wiki/2/friendships/followers">friendships/followers</a>
     * @since JDK 1.5
     */
    public UserWapper getFollowersByName(String screen_name, Integer count,
            Integer cursor) throws WeiboException {
        return User.constructWapperUsers(client.get(
                WeiboConfig.getValue("baseURL") + "friendships/followers.json",
                new PostParameter[] {
                        new PostParameter("screen_name", screen_name),
                        new PostParameter("count", count.toString()),
                        new PostParameter("cursor", cursor.toString()) }));
    }

    /**
     * 获取用户的粉丝列表
     * 
     * @param screen_name
     *            需要查询的用户昵称
     * @return list of users
     * @throws WeiboException
     *             when Weibo service or network is unavailable
     * @version weibo4j-V2 1.0.0
     * @see <a
     *      href="http://open.weibo.com/wiki/2/friendships/followers">friendships/followers</a>
     * @since JDK 1.5
     */
    public UserWapper getFollowersById(String uid) throws WeiboException {
        return User.constructWapperUsers(client.get(
                WeiboConfig.getValue("baseURL") + "friendships/followers.json",
                new PostParameter[] { new PostParameter("uid", uid) }));
    }

    /**
     * 获取用户的粉丝列表
     * 
     * @param screen_name
     *            需要查询的用户昵称
     * @param count
     *            单页返回的记录条数,默认为500,最大不超过5000
     * @param cursor
     *            返回结果的游标,下一页用返回值里的next_cursor,上一页用previous_cursor,默认为0
     * @return list of users
     * @throws WeiboException
     *             when Weibo service or network is unavailable
     * @version weibo4j-V2 1.0.0
     * @see <a
     *      href="http://open.weibo.com/wiki/2/friendships/followers">friendships/followers</a>
     * @since JDK 1.5
     */
    public UserWapper getFollowersById(String uid, Integer count, Integer cursor)
            throws WeiboException {
        return User.constructWapperUsers(client.get(
                WeiboConfig.getValue("baseURL") + "friendships/followers.json",
                new PostParameter[] { new PostParameter("uid", uid),
                        new PostParameter("count", count.toString()),
                        new PostParameter("cursor", cursor.toString()) }));
    }

    /**
     * 获取用户粉丝的用户UID列表
     * 
     * @param uid
     *            需要查询的用户ID
     * @return list of users
     * @throws WeiboException
     *             when Weibo service or network is unavailable
     * @version weibo4j-V2 1.0.0
     * @see <a
     *      href="http://open.weibo.com/wiki/2/friendships/followers/ids">friendships/followers/ids</a>
     * @since JDK 1.5
     */
    public String[] getFollowersIdsById(String uid) throws WeiboException {
        return User.constructIds(client.get(WeiboConfig.getValue("baseURL")
                + "friendships/followers/ids.json",
                new PostParameter[] { new PostParameter("uid", uid) }));
    }

    /**
     * 获取用户粉丝的用户UID列表
     * 
     * @param uid
     *            需要查询的用户ID
     * @param count
     *            单页返回的记录条数,默认为500,最大不超过5000
     * @param cursor
     *            返回结果的游标,下一页用返回值里的next_cursor,上一页用previous_cursor,默认为0
     * @return list of users
     * @throws WeiboException
     *             when Weibo service or network is unavailable
     * @version weibo4j-V2 1.0.0
     * @see <a
     *      href="http://open.weibo.com/wiki/2/friendships/followers/ids">friendships/followers/ids</a>
     * @since JDK 1.5
     */
    public String[] getFollowersIdsById(String uid, Integer count,
            Integer cursor) throws WeiboException {
        return User.constructIds(client.get(WeiboConfig.getValue("baseURL")
                + "friendships/followers/ids.json",
                new PostParameter[] { new PostParameter("uid", uid),
                        new PostParameter("count", count.toString()),
                        new PostParameter("cursor", cursor.toString()) }));
    }

    /**
     * 获取用户粉丝的用户UID列表
     * 
     * @param screen_name
     *            需要查询的用户昵称
     * @return list of users
     * @throws WeiboException
     *             when Weibo service or network is unavailable
     * @version weibo4j-V2 1.0.0
     * @see <a
     *      href="http://open.weibo.com/wiki/2/friendships/followers/ids">friendships/followers/ids</a>
     * @since JDK 1.5
     */
    public String[] getFollowersIdsByName(String screen_name)
            throws WeiboException {
        return User.constructIds(client.get(WeiboConfig.getValue("baseURL")
                + "friendships/followers/ids.json",
                new PostParameter[] { new PostParameter("screen_name",
                        screen_name) }));
    }

    /**
     * 获取用户粉丝的用户UID列表
     * 
     * @param screen_name
     *            需要查询的用户ID
     * @param count
     *            单页返回的记录条数,默认为500,最大不超过5000
     * @param cursor
     *            返回结果的游标,下一页用返回值里的next_cursor,上一页用previous_cursor,默认为0
     * @return list of users
     * @throws WeiboException
     *             when Weibo service or network is unavailable
     * @version weibo4j-V2 1.0.0
     * @see <a
     *      href="http://open.weibo.com/wiki/2/friendships/followers/ids">friendships/followers/ids</a>
     * @since JDK 1.5
     */
    public String[] getFollowersIdsByName(String screen_name, Integer count,
            Integer cursor) throws WeiboException {
        return User.constructIds(client.get(WeiboConfig.getValue("baseURL")
                + "friendships/followers/ids.json", new PostParameter[] {
                new PostParameter("screen_name", screen_name),
                new PostParameter("count", count.toString()),
                new PostParameter("cursor", cursor.toString()) }));
    }

    /**
     * 获取用户的活跃粉丝列表
     * 
     * @param uid
     *            需要查询的用户ID
     * @return list of user's id
     * @throws WeiboException
     *             when Weibo service or network is unavailable
     * @version weibo4j-V2 1.0.0
     * @see <a
     *      href="http://open.weibo.com/wiki/2/friendships/followers/active">friendships/followers/active</a>
     * @since JDK 1.5
     */
    public UserWapper getFollowersActive(String uid) throws WeiboException {
        return User.constructWapperUsers(client.get(
                WeiboConfig.getValue("baseURL")
                        + "friendships/followers/active.json",
                new PostParameter[] { new PostParameter("uid", uid) }));
    }

    /**
     * 获取用户的活跃粉丝列表
     * 
     * @param uid
     *            需要查询的用户ID
     * @param count
     *            返回的记录条数,默认为20,最大不超过200。
     * @return list of users
     * @throws WeiboException
     *             when Weibo service or network is unavailable
     * @version weibo4j-V2 1.0.0
     * @see <a
     *      href="http://open.weibo.com/wiki/2/friendships/followers/active">friendships/followers/active</a>
     * @since JDK 1.5
     */
    public UserWapper getFollowersActive(String uid, Integer count)
            throws WeiboException {
        return User.constructWapperUsers(client.get(
                WeiboConfig.getValue("baseURL")
                        + "friendships/followers/active.json",
                new PostParameter[] { new PostParameter("uid", uid),
                        new PostParameter("count", count.toString()) }));
    }

    /**
     * 获取当前登录用户的关注人中又关注了指定用户的用户列表
     * 
     * @param uid
     *            需要查询的用户ID
     * @return list of users
     * @throws WeiboException
     *             when Weibo service or network is unavailable
     * @version weibo4j-V2 1.0.0
     * @see <a
     *      href="http://open.weibo.com/wiki/2/friendships/friends_chain/followers">friendships/friends_chain/followers</a>
     * @since JDK 1.5
     */
    public UserWapper getFriendsChainFollowers(String uid)
            throws WeiboException {
        return User.constructWapperUsers(client.get(
                WeiboConfig.getValue("baseURL")
                        + "friendships/friends_chain/followers.json",
                new PostParameter[] { new PostParameter("uid", uid) }));
    }

    /**
     * 关注一个用户
     * 
     * @param uid
     *            需要查询的用户ID
     * @return user
     * @throws WeiboException
     *             when Weibo service or network is unavailable
     * @version weibo4j-V2 1.0.0
     * @see <a
     *      href="http://open.weibo.com/wiki/2/friendships/create">friendships/create</a>
     * @since JDK 1.5
     */
    public User createFriendshipsById(String uid) throws WeiboException {
        return new User(client.post(
                WeiboConfig.getValue("baseURL") + "friendships/create.json",
                new PostParameter[] { new PostParameter("uid", uid) })
                .asJSONObject());
    }

    /**
     * 关注一个用户
     * 
     * @param screen_name
     *            需要查询的用户screen_name
     * @return user
     * @throws WeiboException
     *             when Weibo service or network is unavailable
     * @version weibo4j-V2 1.0.0
     * @see <a
     *      href="http://open.weibo.com/wiki/2/friendships/create">friendships/create</a>
     * @since JDK 1.5
     */
    public User createFriendshipsByName(String screen_name)
            throws WeiboException {
        return new User(client.post(
                WeiboConfig.getValue("baseURL") + "friendships/create.json",
                new PostParameter[] { new PostParameter("screen_name",
                        screen_name) }).asJSONObject());
    }

    /**
     * 取消关注一个用户
     * 
     * @param uid
     *            需要查询的用户ID
     * @return user
     * @throws WeiboException
     *             when Weibo service or network is unavailable
     * @version weibo4j-V2 1.0.0
     * @see <a
     *      href="http://open.weibo.com/wiki/2/friendships/destroy">friendships/destroy</a>
     * @since JDK 1.5
     */
    public User destroyFriendshipsDestroyById(String uid) throws WeiboException {
        return new User(client.post(
                WeiboConfig.getValue("baseURL") + "friendships/destroy.json",
                new PostParameter[] { new PostParameter("uid", uid) })
                .asJSONObject());
    }

    /**
     * 取消关注一个用户
     * 
     * @param screen_name
     *            需要查询的用户screen_name
     * @return user
     * @throws WeiboException
     *             when Weibo service or network is unavailable
     * @version weibo4j-V2 1.0.0
     * @see <a
     *      href="http://open.weibo.com/wiki/2/friendships/destroy">friendships/destroy</a>
     * @since JDK 1.5
     */
    public User destroyFriendshipsDestroyByName(String screen_name)
            throws WeiboException {
        return new User(client.post(
                WeiboConfig.getValue("baseURL") + "friendships/destroy.json",
                new PostParameter[] { new PostParameter("screen_name",
                        screen_name) }).asJSONObject());
    }
}

Users.java

package weibo4j;

import weibo4j.model.PostParameter;
import weibo4j.model.User;
import weibo4j.model.WeiboException;
import weibo4j.org.json.JSONArray;
import weibo4j.util.WeiboConfig;

public class Users extends Weibo {

    private static final long serialVersionUID = 4742830953302255953L;

    /*----------------------------用户接口----------------------------------------*/
    /**
     * 根据用户ID获取用户信息
     * 
     * @param uid
     *            需要查询的用户ID
     * @return User
     * @throws WeiboException
     *             when Weibo service or network is unavailable
     * @version weibo4j-V2 1.0.1
     * @see <a href="http://open.weibo.com/wiki/2/users/show">users/show</a>
     * @since JDK 1.5
     */
    public User showUserById(String uid) throws WeiboException {
        return new User(client.get(
                WeiboConfig.getValue("baseURL") + "users/show.json",
                new PostParameter[] { new PostParameter("uid", uid) })
                .asJSONObject());
    }

    /**
     * 根据用户ID获取用户信息
     * 
     * @param screen_name
     *            用户昵称
     * @return User
     * @throws WeiboException
     *             when Weibo service or network is unavailable
     * @version weibo4j-V2 1.0.1
     * @see <a href="http://open.weibo.com/wiki/2/users/show">users/show</a>
     * @since JDK 1.5
     */
    public User showUserByScreenName(String screen_name) throws WeiboException {
        return new User(client.get(
                WeiboConfig.getValue("baseURL") + "users/show.json",
                new PostParameter[] { new PostParameter("screen_name",
                        screen_name) }).asJSONObject());
    }

    /**
     * 通过个性化域名获取用户资料以及用户最新的一条微博
     * 
     * @param domain
     *            需要查询的个性化域名。
     * @return User
     * @throws WeiboException
     *             when Weibo service or network is unavailable
     * @version weibo4j-V2 1.0.1
     * @see <a
     *      href="http://open.weibo.com/wiki/2/users/domain_show">users/domain_show</a>
     * @since JDK 1.5
     */
    public User showUserByDomain(String domain) throws WeiboException {
        return new User(client.get(
                WeiboConfig.getValue("baseURL") + "users/domain_show.json",
                new PostParameter[] { new PostParameter("domain", domain) })
                .asJSONObject());
    }

    /**
     * 批量获取用户的粉丝数、关注数、微博数
     * 
     * @param uids
     *            需要获取数据的用户UID,多个之间用逗号分隔,最多不超过100个
     * @return jsonobject
     * @throws WeiboException
     *             when Weibo service or network is unavailable
     * @version weibo4j-V2 1.0.1
     * @see <a
     *      href="http://open.weibo.com/wiki/2/users/domain_show">users/domain_show</a>
     * @since JDK 1.5
     */
    public JSONArray getUserCount(String uids) throws WeiboException {
        return client.get(
                WeiboConfig.getValue("baseURL") + "users/counts.json",
                new PostParameter[] { new PostParameter("uids", uids) })
                .asJSONArray();
    }
}

Weibo.java

package weibo4j;

import weibo4j.http.HttpClient;

public class Weibo implements java.io.Serializable {

    private static final long serialVersionUID = 4282616848978535016L;

    public HttpClient client = new HttpClient();

    public void setToken(String token) {
        client.setToken(token);
    }

}

weibo4j.http包

AccessToken.java

package weibo4j.http;

import java.io.Serializable;

import weibo4j.model.WeiboException;
import weibo4j.model.WeiboResponse;
import weibo4j.org.json.JSONException;
import weibo4j.org.json.JSONObject;

public class AccessToken extends WeiboResponse implements Serializable {

    private static final long serialVersionUID = 6986530164134648944L;
    private String accessToken;
    private String expireIn;
    private String refreshToken;
    private String uid;

    public AccessToken(Response res) throws WeiboException {
        super(res);
        JSONObject json = res.asJSONObject();
        try {
            accessToken = json.getString("access_token");
            expireIn = json.getString("expires_in");
            refreshToken = json.getString("refresh_token");
            uid = json.getString("uid");
        } catch (JSONException je) {
            throw new WeiboException(je.getMessage() + ":" + json.toString(),
                    je);
        }
    }

    AccessToken(String res) throws WeiboException, JSONException {
        super();
        JSONObject json = new JSONObject(res);
        accessToken = json.getString("access_token");
        expireIn = json.getString("expires_in");
        refreshToken = json.getString("refresh_token");
        uid = json.getString("uid");
    }

    public String getAccessToken() {
        return accessToken;
    }

    public String getExpireIn() {
        return expireIn;
    }

    public String getRefreshToken() {
        return refreshToken;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result
                + ((accessToken == null) ? 0 : accessToken.hashCode());
        result = prime * result
                + ((expireIn == null) ? 0 : expireIn.hashCode());
        result = prime * result
                + ((refreshToken == null) ? 0 : refreshToken.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        AccessToken other = (AccessToken) obj;
        if (accessToken == null) {
            if (other.accessToken != null)
                return false;
        } else if (!accessToken.equals(other.accessToken))
            return false;
        if (expireIn == null) {
            if (other.expireIn != null)
                return false;
        } else if (!expireIn.equals(other.expireIn))
            return false;
        if (refreshToken == null) {
            if (other.refreshToken != null)
                return false;
        } else if (!refreshToken.equals(other.refreshToken))
            return false;
        return true;
    }

    @Override
    public String toString() {
        return "AccessToken [" + "accessToken=" + accessToken + ", expireIn="
                + expireIn + ", refreshToken=" + refreshToken + ",uid=" + uid
                + "]";
    }

}

BASE64Encoder.java


package weibo4j.http;

/**
 * A utility class encodes byte array into String using Base64 encoding scheme.
 * 
 * @see weibo4j.http.HttpClient
 * @author Yusuke Yamamoto - yusuke at mac.com
 */
public class BASE64Encoder {
    private static final char last2byte = (char) Integer
            .parseInt("00000011", 2);
    private static final char last4byte = (char) Integer
            .parseInt("00001111", 2);
    private static final char last6byte = (char) Integer
            .parseInt("00111111", 2);
    private static final char lead6byte = (char) Integer
            .parseInt("11111100", 2);
    private static final char lead4byte = (char) Integer
            .parseInt("11110000", 2);
    private static final char lead2byte = (char) Integer
            .parseInt("11000000", 2);
    private static final char[] encodeTable = new char[] { 'A', 'B', 'C', 'D',
            'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
            'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
            'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
            'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3',
            '4', '5', '6', '7', '8', '9', '+', '/' };

    public BASE64Encoder() {
    }

    public static String encode(byte[] from) {
        StringBuffer to = new StringBuffer((int) (from.length * 1.34) + 3);
        int num = 0;
        char currentByte = 0;
        for (int i = 0; i < from.length; i++) {
            num = num % 8;
            while (num < 8) {
                switch (num) {
                case 0:
                    currentByte = (char) (from[i] & lead6byte);
                    currentByte = (char) (currentByte >>> 2);
                    break;
                case 2:
                    currentByte = (char) (from[i] & last6byte);
                    break;
                case 4:
                    currentByte = (char) (from[i] & last4byte);
                    currentByte = (char) (currentByte << 2);
                    if ((i + 1) < from.length) {
                        currentByte |= (from[i + 1] & lead2byte) >>> 6;
                    }
                    break;
                case 6:
                    currentByte = (char) (from[i] & last2byte);
                    currentByte = (char) (currentByte << 4);
                    if ((i + 1) < from.length) {
                        currentByte |= (from[i + 1] & lead4byte) >>> 4;
                    }
                    break;
                }
                to.append(encodeTable[currentByte]);
                num += 6;
            }
        }
        if (to.length() % 4 != 0) {
            for (int i = 4 - to.length() % 4; i > 0; i--) {
                to.append("=");
            }
        }
        return to.toString();
    }
}

HTMLEntity.java


package weibo4j.http;

import java.util.HashMap;
import java.util.Map;

public class HTMLEntity {
    public static String escape(String original) {
        StringBuffer buf = new StringBuffer(original);
        escape(buf);
        return buf.toString();
    }

    public static void escape(StringBuffer original) {
        int index = 0;
        String escaped;
        while (index < original.length()) {
            escaped = entityEscapeMap.get(original.substring(index, index + 1));
            if (null != escaped) {
                original.replace(index, index + 1, escaped);
                index += escaped.length();
            } else {
                index++;
            }
        }
    }

    public static String unescape(String original) {
        StringBuffer buf = new StringBuffer(original);
        unescape(buf);
        return buf.toString();
    }

    public static void unescape(StringBuffer original) {
        int index = 0;
        int semicolonIndex = 0;
        String escaped;
        String entity;
        while (index < original.length()) {
            index = original.indexOf("&", index);
            if (-1 == index) {
                break;
            }
            semicolonIndex = original.indexOf(";", index);
            if (-1 != semicolonIndex && 10 > (semicolonIndex - index)) {
                escaped = original.substring(index, semicolonIndex + 1);
                entity = escapeEntityMap.get(escaped);
                if (null != entity) {
                    original.replace(index, semicolonIndex + 1, entity);
                }
                index++;
            } else {
                break;
            }
        }
    }

    private static Map<String, String> entityEscapeMap = new HashMap<String, String>();
    private static Map<String, String> escapeEntityMap = new HashMap<String, String>();

    static {
        String[][] entities = {
                { "&nbsp;", "&#160;"/* no-break space = non-breaking space */,
                        "\u00A0" },
                { "&iexcl;", "&#161;"/* inverted exclamation mark */, "\u00A1" },
                { "&cent;", "&#162;"/* cent sign */, "\u00A2" },
                { "&pound;", "&#163;"/* pound sign */, "\u00A3" },
                { "&curren;", "&#164;"/* currency sign */, "\u00A4" },
                { "&yen;", "&#165;"/* yen sign = yuan sign */, "\u00A5" },
                { "&brvbar;", "&#166;"/* broken bar = broken vertical bar */,
                        "\u00A6" },
                { "&sect;", "&#167;"/* section sign */, "\u00A7" },
                { "&uml;", "&#168;"/* diaeresis = spacing diaeresis */,
                        "\u00A8" },
                { "&copy;", "&#169;"/* copyright sign */, "\u00A9" },
                { "&ordf;", "&#170;"/* feminine ordinal indicator */, "\u00AA" },
                { "&laquo;", "&#171;"/*
                                     * left-pointing double angle quotation mark
                                     * = left pointing guillemet
                                     */, "\u00AB" },
                { "&not;", "&#172;"/* not sign = discretionary hyphen */,
                        "\u00AC" },
                { "&shy;", "&#173;"/* soft hyphen = discretionary hyphen */,
                        "\u00AD" },
                { "&reg;", "&#174;"/*
                                     * registered sign = registered trade mark
                                     * sign
                                     */, "\u00AE" },
                { "&macr;", "&#175;"/*
                                     * macron = spacing macron = overline = APL
                                     * overbar
                                     */, "\u00AF" },
                { "&deg;", "&#176;"/* degree sign */, "\u00B0" },
                { "&plusmn;", "&#177;"/* plus-minus sign = plus-or-minus sign */,
                        "\u00B1" },
                { "&sup2;", "&#178;"/*
                                     * superscript two = superscript digit two =
                                     * squared
                                     */, "\u00B2" },
                { "&sup3;", "&#179;"/*
                                     * superscript three = superscript digit
                                     * three = cubed
                                     */, "\u00B3" },
                { "&acute;", "&#180;"/* acute accent = spacing acute */,
                        "\u00B4" },
                { "&micro;", "&#181;"/* micro sign */, "\u00B5" },
                { "&para;", "&#182;"/* pilcrow sign = paragraph sign */,
                        "\u00B6" },
                { "&middot;", "&#183;"/*
                                     * middle dot = Georgian comma = Greek
                                     * middle dot
                                     */, "\u00B7" },
                { "&cedil;", "&#184;"/* cedilla = spacing cedilla */, "\u00B8" },
                { "&sup1;",
                        "&#185;"/* superscript one = superscript digit one */,
                        "\u00B9" },
                { "&ordm;", "&#186;"/* masculine ordinal indicator */, "\u00BA" },
                { "&raquo;", "&#187;"/*
                                     * right-pointing double angle quotation
                                     * mark = right pointing guillemet
                                     */, "\u00BB" },
                { "&frac14;", "&#188;"/*
                                     * vulgar fraction one quarter = fraction
                                     * one quarter
                                     */, "\u00BC" },
                { "&frac12;", "&#189;"/*
                                     * vulgar fraction one half = fraction one
                                     * half
                                     */, "\u00BD" },
                { "&frac34;", "&#190;"/*
                                     * vulgar fraction three quarters = fraction
                                     * three quarters
                                     */, "\u00BE" },
                { "&iquest;", "&#191;"/*
                                     * inverted question mark = turned question
                                     * mark
                                     */, "\u00BF" },
                { "&Agrave;", "&#192;"/*
                                     * latin capital letter A with grave = latin
                                     * capital letter A grave
                                     */, "\u00C0" },
                { "&Aacute;", "&#193;"/* latin capital letter A with acute */,
                        "\u00C1" },
                { "&Acirc;",
                        "&#194;"/* latin capital letter A with circumflex */,
                        "\u00C2" },
                { "&Atilde;", "&#195;"/* latin capital letter A with tilde */,
                        "\u00C3" },
                { "&Auml;",
                        "&#196;"/* latin capital letter A with diaeresis */,
                        "\u00C4" },
                { "&Aring;", "&#197;"/*
                                     * latin capital letter A with ring above =
                                     * latin capital letter A ring
                                     */, "\u00C5" },
                { "&AElig;", "&#198;"/*
                                     * latin capital letter AE = latin capital
                                     * ligature AE
                                     */, "\u00C6" },
                { "&Ccedil;", "&#199;"/* latin capital letter C with cedilla */,
                        "\u00C7" },
                { "&Egrave;", "&#200;"/* latin capital letter E with grave */,
                        "\u00C8" },
                { "&Eacute;", "&#201;"/* latin capital letter E with acute */,
                        "\u00C9" },
                { "&Ecirc;",
                        "&#202;"/* latin capital letter E with circumflex */,
                        "\u00CA" },
                { "&Euml;",
                        "&#203;"/* latin capital letter E with diaeresis */,
                        "\u00CB" },
                { "&Igrave;", "&#204;"/* latin capital letter I with grave */,
                        "\u00CC" },
                { "&Iacute;", "&#205;"/* latin capital letter I with acute */,
                        "\u00CD" },
                { "&Icirc;",
                        "&#206;"/* latin capital letter I with circumflex */,
                        "\u00CE" },
                { "&Iuml;",
                        "&#207;"/* latin capital letter I with diaeresis */,
                        "\u00CF" },
                { "&ETH;", "&#208;"/* latin capital letter ETH */, "\u00D0" },
                { "&Ntilde;", "&#209;"/* latin capital letter N with tilde */,
                        "\u00D1" },
                { "&Ograve;", "&#210;"/* latin capital letter O with grave */,
                        "\u00D2" },
                { "&Oacute;", "&#211;"/* latin capital letter O with acute */,
                        "\u00D3" },
                { "&Ocirc;",
                        "&#212;"/* latin capital letter O with circumflex */,
                        "\u00D4" },
                { "&Otilde;", "&#213;"/* latin capital letter O with tilde */,
                        "\u00D5" },
                { "&Ouml;",
                        "&#214;"/* latin capital letter O with diaeresis */,
                        "\u00D6" },
                { "&times;", "&#215;"/* multiplication sign */, "\u00D7" },
                { "&Oslash;", "&#216;"/*
                                     * latin capital letter O with stroke =
                                     * latin capital letter O slash
                                     */, "\u00D8" },
                { "&Ugrave;", "&#217;"/* latin capital letter U with grave */,
                        "\u00D9" },
                { "&Uacute;", "&#218;"/* latin capital letter U with acute */,
                        "\u00DA" },
                { "&Ucirc;",
                        "&#219;"/* latin capital letter U with circumflex */,
                        "\u00DB" },
                { "&Uuml;",
                        "&#220;"/* latin capital letter U with diaeresis */,
                        "\u00DC" },
                { "&Yacute;", "&#221;"/* latin capital letter Y with acute */,
                        "\u00DD" },
                { "&THORN;", "&#222;"/* latin capital letter THORN */, "\u00DE" },
                { "&szlig;", "&#223;"/* latin small letter sharp s = ess-zed */,
                        "\u00DF" },
                { "&agrave;", "&#224;"/*
                                     * latin small letter a with grave = latin
                                     * small letter a grave
                                     */, "\u00E0" },
                { "&aacute;", "&#225;"/* latin small letter a with acute */,
                        "\u00E1" },
                { "&acirc;", "&#226;"/* latin small letter a with circumflex */,
                        "\u00E2" },
                { "&atilde;", "&#227;"/* latin small letter a with tilde */,
                        "\u00E3" },
                { "&auml;", "&#228;"/* latin small letter a with diaeresis */,
                        "\u00E4" },
                { "&aring;", "&#229;"/*
                                     * latin small letter a with ring above =
                                     * latin small letter a ring
                                     */, "\u00E5" },
                { "&aelig;", "&#230;"/*
                                     * latin small letter ae = latin small
                                     * ligature ae
                                     */, "\u00E6" },
                { "&ccedil;", "&#231;"/* latin small letter c with cedilla */,
                        "\u00E7" },
                { "&egrave;", "&#232;"/* latin small letter e with grave */,
                        "\u00E8" },
                { "&eacute;", "&#233;"/* latin small letter e with acute */,
                        "\u00E9" },
                { "&ecirc;", "&#234;"/* latin small letter e with circumflex */,
                        "\u00EA" },
                { "&euml;", "&#235;"/* latin small letter e with diaeresis */,
                        "\u00EB" },
                { "&igrave;", "&#236;"/* latin small letter i with grave */,
                        "\u00EC" },
                { "&iacute;", "&#237;"/* latin small letter i with acute */,
                        "\u00ED" },
                { "&icirc;", "&#238;"/* latin small letter i with circumflex */,
                        "\u00EE" },
                { "&iuml;", "&#239;"/* latin small letter i with diaeresis */,
                        "\u00EF" },
                { "&eth;", "&#240;"/* latin small letter eth */, "\u00F0" },
                { "&ntilde;", "&#241;"/* latin small letter n with tilde */,
                        "\u00F1" },
                { "&ograve;", "&#242;"/* latin small letter o with grave */,
                        "\u00F2" },
                { "&oacute;", "&#243;"/* latin small letter o with acute */,
                        "\u00F3" },
                { "&ocirc;", "&#244;"/* latin small letter o with circumflex */,
                        "\u00F4" },
                { "&otilde;", "&#245;"/* latin small letter o with tilde */,
                        "\u00F5" },
                { "&ouml;", "&#246;"/* latin small letter o with diaeresis */,
                        "\u00F6" },
                { "&divide;", "&#247;"/* division sign */, "\u00F7" },
                { "&oslash;", "&#248;"/*
                                     * latin small letter o with stroke = latin
                                     * small letter o slash
                                     */, "\u00F8" },
                { "&ugrave;", "&#249;"/* latin small letter u with grave */,
                        "\u00F9" },
                { "&uacute;", "&#250;"/* latin small letter u with acute */,
                        "\u00FA" },
                { "&ucirc;", "&#251;"/* latin small letter u with circumflex */,
                        "\u00FB" },
                { "&uuml;", "&#252;"/* latin small letter u with diaeresis */,
                        "\u00FC" },
                { "&yacute;", "&#253;"/* latin small letter y with acute */,
                        "\u00FD" },
                { "&thorn;", "&#254;"/* latin small letter thorn with */,
                        "\u00FE" },
                { "&yuml;", "&#255;"/* latin small letter y with diaeresis */,
                        "\u00FF" },
                { "&fnof;", "&#402;"/*
                                     * latin small f with hook = function =
                                     * florin
                                     */, "\u0192" }
                /* Greek */
                ,
                { "&Alpha;", "&#913;"/* greek capital letter alpha */, "\u0391" },
                { "&Beta;", "&#914;"/* greek capital letter beta */, "\u0392" },
                { "&Gamma;", "&#915;"/* greek capital letter gamma */, "\u0393" },
                { "&Delta;", "&#916;"/* greek capital letter delta */, "\u0394" },
                { "&Epsilon;", "&#917;"/* greek capital letter epsilon */,
                        "\u0395" },
                { "&Zeta;", "&#918;"/* greek capital letter zeta */, "\u0396" },
                { "&Eta;", "&#919;"/* greek capital letter eta */, "\u0397" },
                { "&Theta;", "&#920;"/* greek capital letter theta */, "\u0398" },
                { "&Iota;", "&#921;"/* greek capital letter iota */, "\u0399" },
                { "&Kappa;", "&#922;"/* greek capital letter kappa */, "\u039A" },
                { "&Lambda;", "&#923;"/* greek capital letter lambda */, "\u039B" },
                { "&Mu;", "&#924;"/* greek capital letter mu */, "\u039C" },
                { "&Nu;", "&#925;"/* greek capital letter nu */, "\u039D" },
                { "&Xi;", "&#926;"/* greek capital letter xi */, "\u039E" },
                { "&Omicron;", "&#927;"/* greek capital letter omicron */,
                        "\u039F" },
                { "&Pi;", "&#928;"/* greek capital letter pi */, "\u03A0" },
                { "&Rho;", "&#929;"/* greek capital letter rho */, "\u03A1" }
                /* there is no Sigmaf and no \u03A2 */
                ,
                { "&Sigma;", "&#931;"/* greek capital letter sigma */, "\u03A3" },
                { "&Tau;", "&#932;"/* greek capital letter tau */, "\u03A4" },
                { "&Upsilon;", "&#933;"/* greek capital letter upsilon */,
                        "\u03A5" },
                { "&Phi;", "&#934;"/* greek capital letter phi */, "\u03A6" },
                { "&Chi;", "&#935;"/* greek capital letter chi */, "\u03A7" },
                { "&Psi;", "&#936;"/* greek capital letter psi */, "\u03A8" },
                { "&Omega;", "&#937;"/* greek capital letter omega */, "\u03A9" },
                { "&alpha;", "&#945;"/* greek small letter alpha */, "\u03B1" },
                { "&beta;", "&#946;"/* greek small letter beta */, "\u03B2" },
                { "&gamma;", "&#947;"/* greek small letter gamma */, "\u03B3" },
                { "&delta;", "&#948;"/* greek small letter delta */, "\u03B4" },
                { "&epsilon;", "&#949;"/* greek small letter epsilon */,
                        "\u03B5" },
                { "&zeta;", "&#950;"/* greek small letter zeta */, "\u03B6" },
                { "&eta;", "&#951;"/* greek small letter eta */, "\u03B7" },
                { "&theta;", "&#952;"/* greek small letter theta */, "\u03B8" },
                { "&iota;", "&#953;"/* greek small letter iota */, "\u03B9" },
                { "&kappa;", "&#954;"/* greek small letter kappa */, "\u03BA" },
                { "&lambda;", "&#955;"/* greek small letter lambda */, "\u03BB" },
                { "&mu;", "&#956;"/* greek small letter mu */, "\u03BC" },
                { "&nu;", "&#957;"/* greek small letter nu */, "\u03BD" },
                { "&xi;", "&#958;"/* greek small letter xi */, "\u03BE" },
                { "&omicron;", "&#959;"/* greek small letter omicron */,
                        "\u03BF" },
                { "&pi;", "&#960;"/* greek small letter pi */, "\u03C0" },
                { "&rho;", "&#961;"/* greek small letter rho */, "\u03C1" },
                { "&sigmaf;", "&#962;"/* greek small letter final sigma */,
                        "\u03C2" },
                { "&sigma;", "&#963;"/* greek small letter sigma */, "\u03C3" },
                { "&tau;", "&#964;"/* greek small letter tau */, "\u03C4" },
                { "&upsilon;", "&#965;"/* greek small letter upsilon */,
                        "\u03C5" },
                { "&phi;", "&#966;"/* greek small letter phi */, "\u03C6" },
                { "&chi;", "&#967;"/* greek small letter chi */, "\u03C7" },
                { "&psi;", "&#968;"/* greek small letter psi */, "\u03C8" },
                { "&omega;", "&#969;"/* greek small letter omega */, "\u03C9" },
                { "&thetasym;", "&#977;"/* greek small letter theta symbol */,
                        "\u03D1" },
                { "&upsih;", "&#978;"/* greek upsilon with hook symbol */,
                        "\u03D2" },
                { "&piv;", "&#982;"/* greek pi symbol */, "\u03D6" }
                /* General Punctuation */
                ,
                { "&bull;", "&#8226;"/* bullet = black small circle */, "\u2022" }
                /* bullet is NOT the same as bullet operator ,"\u2219 */
                ,
                { "&hellip;", "&#8230;"/*
                                         * horizontal ellipsis = three dot
                                         * leader
                                         */, "\u2026" },
                { "&prime;", "&#8242;"/* prime = minutes = feet */, "\u2032" },
                { "&Prime;", "&#8243;"/* double prime = seconds = inches */,
                        "\u2033" },
                { "&oline;", "&#8254;"/* overline = spacing overscore */,
                        "\u203E" },
                { "&frasl;", "&#8260;"/* fraction slash */, "\u2044" }
                /* Letterlike Symbols */
                ,
                { "&weierp;", "&#8472;"/*
                                         * script capital P = power set =
                                         * Weierstrass p
                                         */, "\u2118" },
                { "&image;",
                        "&#8465;"/* blackletter capital I = imaginary part */,
                        "\u2111" },
                { "&real;",
                        "&#8476;"/* blackletter capital R = real part symbol */,
                        "\u211C" },
                { "&trade;", "&#8482;"/* trade mark sign */, "\u2122" },
                { "&alefsym;", "&#8501;"/*
                                         * alef symbol = first transfinite
                                         * cardinal
                                         */, "\u2135" }
                /* alef symbol is NOT the same as hebrew letter alef ,"\u05D0"} */
                /* Arrows */
                ,
                { "&larr;", "&#8592;"/* leftwards arrow */, "\u2190" },
                { "&uarr;", "&#8593;"/* upwards arrow */, "\u2191" },
                { "&rarr;", "&#8594;"/* rightwards arrow */, "\u2192" },
                { "&darr;", "&#8595;"/* downwards arrow */, "\u2193" },
                { "&harr;", "&#8596;"/* left right arrow */, "\u2194" },
                { "&crarr;", "&#8629;"/*
                                     * downwards arrow with corner leftwards =
                                     * carriage return
                                     */, "\u21B5" },
                { "&lArr;", "&#8656;"/* leftwards double arrow */, "\u21D0" }
                /*
                 * Unicode does not say that lArr is the same as the 'is implied
                 * by' arrow but also does not have any other character for that
                 * function. So ? lArr can be used for 'is implied by' as
                 * ISOtech suggests
                 */
                ,
                { "&uArr;", "&#8657;"/* upwards double arrow */, "\u21D1" },
                { "&rArr;", "&#8658;"/* rightwards double arrow */, "\u21D2" }
                /*
                 * Unicode does not say this is the 'implies' character but does
                 * not have another character with this function so ? rArr can
                 * be used for 'implies' as ISOtech suggests
                 */
                ,
                { "&dArr;", "&#8659;"/* downwards double arrow */, "\u21D3" },
                { "&hArr;", "&#8660;"/* left right double arrow */, "\u21D4" }
                /* Mathematical Operators */
                ,
                { "&forall;", "&#8704;"/* for all */, "\u2200" },
                { "&part;", "&#8706;"/* partial differential */, "\u2202" },
                { "&exist;", "&#8707;"/* there exists */, "\u2203" },
                { "&empty;", "&#8709;"/* empty set = null set = diameter */,
                        "\u2205" },
                { "&nabla;", "&#8711;"/* nabla = backward difference */, "\u2207" },
                { "&isin;", "&#8712;"/* element of */, "\u2208" },
                { "&notin;", "&#8713;"/* not an element of */, "\u2209" },
                { "&ni;", "&#8715;"/* contains as member */, "\u220B" }
                /* should there be a more memorable name than 'ni'? */
                ,
                { "&prod;", "&#8719;"/* n-ary product = product sign */,
                        "\u220F" }
                /* prod is NOT the same character as ,"\u03A0"} */
                ,
                { "&sum;", "&#8721;"/* n-ary sumation */, "\u2211" }
                /* sum is NOT the same character as ,"\u03A3"} */
                ,
                { "&minus;", "&#8722;"/* minus sign */, "\u2212" },
                { "&lowast;", "&#8727;"/* asterisk operator */, "\u2217" },
                { "&radic;", "&#8730;"/* square root = radical sign */, "\u221A" },
                { "&prop;", "&#8733;"/* proportional to */, "\u221D" },
                { "&infin;", "&#8734;"/* infinity */, "\u221E" },
                { "&ang;", "&#8736;"/* angle */, "\u2220" },
                { "&and;", "&#8743;"/* logical and = wedge */, "\u2227" },
                { "&or;", "&#8744;"/* logical or = vee */, "\u2228" },
                { "&cap;", "&#8745;"/* intersection = cap */, "\u2229" },
                { "&cup;", "&#8746;"/* union = cup */, "\u222A" },
                { "&int;", "&#8747;"/* integral */, "\u222B" },
                { "&there4;", "&#8756;"/* therefore */, "\u2234" },
                {
                        "&sim;",
                        "&#8764;"/* tilde operator = varies with = similar to */,
                        "\u223C" }
                /*
                 * tilde operator is NOT the same character as the tilde
                 * ,"\u007E"}
                 */
                ,
                { "&cong;", "&#8773;"/* approximately equal to */, "\u2245" },
                { "&asymp;", "&#8776;"/* almost equal to = asymptotic to */,
                        "\u2248" },
                { "&ne;", "&#8800;"/* not equal to */, "\u2260" },
                { "&equiv;", "&#8801;"/* identical to */, "\u2261" },
                { "&le;", "&#8804;"/* less-than or equal to */, "\u2264" },
                { "&ge;", "&#8805;"/* greater-than or equal to */, "\u2265" },
                { "&sub;", "&#8834;"/* subset of */, "\u2282" },
                { "&sup;", "&#8835;"/* superset of */, "\u2283" }
                /* note that nsup 'not a superset of ,"\u2283"} */
                ,
                { "&sube;", "&#8838;"/* subset of or equal to */, "\u2286" },
                { "&supe;", "&#8839;"/* superset of or equal to */, "\u2287" },
                { "&oplus;", "&#8853;"/* circled plus = direct sum */, "\u2295" },
                { "&otimes;", "&#8855;"/* circled times = vector product */,
                        "\u2297" },
                { "&perp;",
                        "&#8869;"/* up tack = orthogonal to = perpendicular */,
                        "\u22A5" },
                { "&sdot;", "&#8901;"/* dot operator */, "\u22C5" }
                /*
                 * dot operator is NOT the same character as ,"\u00B7"} /*
                 * Miscellaneous Technical
                 */
                ,
                { "&lceil;", "&#8968;"/* left ceiling = apl upstile */, "\u2308" },
                { "&rceil;", "&#8969;"/* right ceiling */, "\u2309" },
                { "&lfloor;", "&#8970;"/* left floor = apl downstile */,
                        "\u230A" },
                { "&rfloor;", "&#8971;"/* right floor */, "\u230B" },
                { "&lang;", "&#9001;"/* left-pointing angle bracket = bra */,
                        "\u2329" }
                /* lang is NOT the same character as ,"\u003C"} */
                ,
                { "&rang;", "&#9002;"/* right-pointing angle bracket = ket */,
                        "\u232A" }
                /* rang is NOT the same character as ,"\u003E"} */
                /* Geometric Shapes */
                ,
                { "&loz;", "&#9674;"/* lozenge */, "\u25CA" }
                /* Miscellaneous Symbols */
                ,
                { "&spades;", "&#9824;"/* black spade suit */, "\u2660" }
                /* black here seems to mean filled as opposed to hollow */
                ,
                { "&clubs;", "&#9827;"/* black club suit = shamrock */, "\u2663" },
                { "&hearts;", "&#9829;"/* black heart suit = valentine */,
                        "\u2665" },
                { "&diams;", "&#9830;"/* black diamond suit */, "\u2666" },
                { "&quot;", "&#34;" /* quotation mark = APL quote */, "\"" },
                { "&amp;", "&#38;" /* ampersand */, "\u0026" },
                { "&lt;", "&#60;" /* less-than sign */, "\u003C" },
                { "&gt;", "&#62;" /* greater-than sign */, "\u003E" }
                /* Latin Extended-A */
                ,
                { "&OElig;", "&#338;" /* latin capital ligature OE */, "\u0152" },
                { "&oelig;", "&#339;" /* latin small ligature oe */, "\u0153" }
                /*
                 * ligature is a misnomer this is a separate character in some
                 * languages
                 */
                ,
                { "&Scaron;",
                        "&#352;" /* latin capital letter S with caron */,
                        "\u0160" },
                { "&scaron;", "&#353;" /* latin small letter s with caron */,
                        "\u0161" },
                { "&Yuml;",
                        "&#376;" /* latin capital letter Y with diaeresis */,
                        "\u0178" }
                /* Spacing Modifier Letters */
                ,
                { "&circ;", "&#710;" /* modifier letter circumflex accent */,
                        "\u02C6" },
                { "&tilde;", "&#732;" /* small tilde */, "\u02DC" }
                /* General Punctuation */
                ,
                { "&ensp;", "&#8194;"/* en space */, "\u2002" },
                { "&emsp;", "&#8195;"/* em space */, "\u2003" },
                { "&thinsp;", "&#8201;"/* thin space */, "\u2009" },
                { "&zwnj;", "&#8204;"/* zero width non-joiner */, "\u200C" },
                { "&zwj;", "&#8205;"/* zero width joiner */, "\u200D" },
                { "&lrm;", "&#8206;"/* left-to-right mark */, "\u200E" },
                { "&rlm;", "&#8207;"/* right-to-left mark */, "\u200F" },
                { "&ndash;", "&#8211;"/* en dash */, "\u2013" },
                { "&mdash;", "&#8212;"/* em dash */, "\u2014" },
                { "&lsquo;", "&#8216;"/* left single quotation mark */, "\u2018" },
                { "&rsquo;", "&#8217;"/* right single quotation mark */, "\u2019" },
                { "&sbquo;", "&#8218;"/* single low-9 quotation mark */, "\u201A" },
                { "&ldquo;", "&#8220;"/* left double quotation mark */, "\u201C" },
                { "&rdquo;", "&#8221;"/* right double quotation mark */, "\u201D" },
                { "&bdquo;", "&#8222;"/* double low-9 quotation mark */, "\u201E" },
                { "&dagger;", "&#8224;"/* dagger */, "\u2020" },
                { "&Dagger;", "&#8225;"/* double dagger */, "\u2021" },
                { "&permil;", "&#8240;"/* per mille sign */, "\u2030" },
                { "&lsaquo;", "&#8249;"/*
                                         * single left-pointing angle quotation
                                         * mark
                                         */, "\u2039" }
                /* lsaquo is proposed but not yet ISO standardized */
                , { "&rsaquo;", "&#8250;"/*
                                         * single right-pointing angle quotation
                                         * mark
                                         */, "\u203A" }
                /* rsaquo is proposed but not yet ISO standardized */
                , { "&euro;", "&#8364;" /* euro sign */, "\u20AC" } };
        for (String[] entity : entities) {
            entityEscapeMap.put(entity[2], entity[0]);
            escapeEntityMap.put(entity[0], entity[2]);
            escapeEntityMap.put(entity[1], entity[2]);
        }
    }

}

HttpClient.java

package weibo4j.http;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

import javax.activation.MimetypesFileTypeMap;

import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.methods.DeleteMethod;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.multipart.FilePart;
import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
import org.apache.commons.httpclient.methods.multipart.Part;
import org.apache.commons.httpclient.methods.multipart.PartBase;
import org.apache.commons.httpclient.methods.multipart.StringPart;
import org.apache.commons.httpclient.params.HttpClientParams;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.log4j.Logger;

import weibo4j.model.Configuration;
import weibo4j.model.MySSLSocketFactory;
import weibo4j.model.Paging;
import weibo4j.model.PostParameter;
import weibo4j.model.WeiboException;
import weibo4j.org.json.JSONException;

/**
 * @author sinaWeibo
 * 
 */
public class HttpClient implements java.io.Serializable {

    private static final long serialVersionUID = -176092625883595547L;
    private static final int OK = 200; // OK: Success!
    private static final int NOT_MODIFIED = 304; // Not Modified: There was no
                                                    // new data to return.
    private static final int BAD_REQUEST = 400; // Bad Request: The request was
                                                // invalid. An accompanying
                                                // error message will explain
                                                // why. This is the status code
                                                // will be returned during rate
                                                // limiting.
    private static final int NOT_AUTHORIZED = 401; // Not Authorized:
                                                    // Authentication
                                                    // credentials were missing
                                                    // or incorrect.
    private static final int FORBIDDEN = 403; // Forbidden: The request is
                                                // understood, but it has been
                                                // refused. An accompanying
                                                // error message will explain
                                                // why.
    private static final int NOT_FOUND = 404; // Not Found: The URI requested is
                                                // invalid or the resource
                                                // requested, such as a user,
                                                // does not exists.
    private static final int NOT_ACCEPTABLE = 406; // Not Acceptable: Returned
                                                    // by the Search API when an
                                                    // invalid format is
                                                    // specified in the request.
    private static final int INTERNAL_SERVER_ERROR = 500;// Internal Server
                                                            // Error: Something
                                                            // is broken. Please
                                                            // post to the group
                                                            // so the Weibo team
                                                            // can investigate.
    private static final int BAD_GATEWAY = 502;// Bad Gateway: Weibo is down or
                                                // being upgraded.
    private static final int SERVICE_UNAVAILABLE = 503;// Service Unavailable:
                                                        // The Weibo servers are
                                                        // up, but overloaded
                                                        // with requests. Try
                                                        // again later. The
                                                        // search and trend
                                                        // methods use this to
                                                        // indicate when you are
                                                        // being rate limited.

    private String proxyHost = Configuration.getProxyHost();
    private int proxyPort = Configuration.getProxyPort();
    private String proxyAuthUser = Configuration.getProxyUser();
    private String proxyAuthPassword = Configuration.getProxyPassword();
    private String token;

    public String getProxyHost() {
        return proxyHost;
    }

    /**
     * Sets proxy host. System property -Dsinat4j.http.proxyHost or
     * http.proxyHost overrides this attribute.
     * 
     * @param proxyHost
     */
    public void setProxyHost(String proxyHost) {
        this.proxyHost = Configuration.getProxyHost(proxyHost);
    }

    public int getProxyPort() {
        return proxyPort;
    }

    /**
     * Sets proxy port. System property -Dsinat4j.http.proxyPort or
     * -Dhttp.proxyPort overrides this attribute.
     * 
     * @param proxyPort
     */
    public void setProxyPort(int proxyPort) {
        this.proxyPort = Configuration.getProxyPort(proxyPort);
    }

    public String getProxyAuthUser() {
        return proxyAuthUser;
    }

    /**
     * Sets proxy authentication user. System property -Dsinat4j.http.proxyUser
     * overrides this attribute.
     * 
     * @param proxyAuthUser
     */
    public void setProxyAuthUser(String proxyAuthUser) {
        this.proxyAuthUser = Configuration.getProxyUser(proxyAuthUser);
    }

    public String getProxyAuthPassword() {
        return proxyAuthPassword;
    }

    /**
     * Sets proxy authentication password. System property
     * -Dsinat4j.http.proxyPassword overrides this attribute.
     * 
     * @param proxyAuthPassword
     */
    public void setProxyAuthPassword(String proxyAuthPassword) {
        this.proxyAuthPassword = Configuration
                .getProxyPassword(proxyAuthPassword);
    }

    public String setToken(String token) {
        this.token = token;
        return this.token;
    }

    private final static boolean DEBUG = Configuration.getDebug();
    static Logger log = Logger.getLogger(HttpClient.class.getName());
    org.apache.commons.httpclient.HttpClient client = null;

    private MultiThreadedHttpConnectionManager connectionManager;
    private int maxSize;

    public HttpClient() {
        this(150, 30000, 30000, 1024 * 1024);
    }

    public HttpClient(int maxConPerHost, int conTimeOutMs, int soTimeOutMs,
            int maxSize) {
        connectionManager = new MultiThreadedHttpConnectionManager();
        HttpConnectionManagerParams params = connectionManager.getParams();
        params.setDefaultMaxConnectionsPerHost(maxConPerHost);
        params.setConnectionTimeout(conTimeOutMs);
        params.setSoTimeout(soTimeOutMs);

        HttpClientParams clientParams = new HttpClientParams();
        // 忽略cookie 避免 Cookie rejected 警告
        clientParams.setCookiePolicy(CookiePolicy.IGNORE_COOKIES);
        client = new org.apache.commons.httpclient.HttpClient(clientParams,
                connectionManager);
        Protocol myhttps = new Protocol("https", new MySSLSocketFactory(), 443);
        Protocol.registerProtocol("https", myhttps);
        this.maxSize = maxSize;
        // 支持proxy
        if (proxyHost != null && !proxyHost.equals("")) {
            client.getHostConfiguration().setProxy(proxyHost, proxyPort);
            client.getParams().setAuthenticationPreemptive(true);
            if (proxyAuthUser != null && !proxyAuthUser.equals("")) {
                client.getState().setProxyCredentials(
                        AuthScope.ANY,
                        new UsernamePasswordCredentials(proxyAuthUser,
                                proxyAuthPassword));
                log("Proxy AuthUser: " + proxyAuthUser);
                log("Proxy AuthPassword: " + proxyAuthPassword);
            }
        }
    }

    /**
     * log调试
     * 
     */
    private static void log(String message) {
        if (DEBUG) {
            log.debug(message);
        }
    }

    /**
     * 处理http getmethod 请求
     * 
     */

    public Response get(String url) throws WeiboException {

        return get(url, new PostParameter[0]);

    }

    public Response get(String url, PostParameter[] params)
            throws WeiboException {
        log("Request:");
        log("GET:" + url);
        if (null != params && params.length > 0) {
            String encodedParams = HttpClient.encodeParameters(params);
            if (-1 == url.indexOf("?")) {
                url += "?" + encodedParams;
            } else {
                url += "&" + encodedParams;
            }
        }
        GetMethod getmethod = new GetMethod(url);
        return httpRequest(getmethod);

    }

    public Response get(String url, PostParameter[] params, Paging paging)
            throws WeiboException {
        if (null != paging) {
            List<PostParameter> pagingParams = new ArrayList<PostParameter>(4);
            if (-1 != paging.getMaxId()) {
                pagingParams.add(new PostParameter("max_id", String
                        .valueOf(paging.getMaxId())));
            }
            if (-1 != paging.getSinceId()) {
                pagingParams.add(new PostParameter("since_id", String
                        .valueOf(paging.getSinceId())));
            }
            if (-1 != paging.getPage()) {
                pagingParams.add(new PostParameter("page", String
                        .valueOf(paging.getPage())));
            }
            if (-1 != paging.getCount()) {
                if (-1 != url.indexOf("search")) {
                    // search api takes "rpp"
                    pagingParams.add(new PostParameter("rpp", String
                            .valueOf(paging.getCount())));
                } else {
                    pagingParams.add(new PostParameter("count", String
                            .valueOf(paging.getCount())));
                }
            }
            PostParameter[] newparams = null;
            PostParameter[] arrayPagingParams = pagingParams
                    .toArray(new PostParameter[pagingParams.size()]);
            if (null != params) {
                newparams = new PostParameter[params.length
                        + pagingParams.size()];
                System.arraycopy(params, 0, newparams, 0, params.length);
                System.arraycopy(arrayPagingParams, 0, newparams,
                        params.length, pagingParams.size());
            } else {
                if (0 != arrayPagingParams.length) {
                    String encodedParams = HttpClient
                            .encodeParameters(arrayPagingParams);
                    if (-1 != url.indexOf("?")) {
                        url += "&" + encodedParams;
                    } else {
                        url += "?" + encodedParams;
                    }
                }
            }
            return get(url, newparams);
        } else {
            return get(url, params);
        }
    }

    /**
     * 处理http deletemethod请求
     */

    public Response delete(String url, PostParameter[] params)
            throws WeiboException {
        if (0 != params.length) {
            String encodedParams = HttpClient.encodeParameters(params);
            if (-1 == url.indexOf("?")) {
                url += "?" + encodedParams;
            } else {
                url += "&" + encodedParams;
            }
        }
        DeleteMethod deleteMethod = new DeleteMethod(url);
        return httpRequest(deleteMethod);

    }

    /**
     * 处理http post请求
     * 
     */

    public Response post(String url, PostParameter[] params)
            throws WeiboException {
        return post(url, params, true);

    }

    public Response post(String url, PostParameter[] params,
            Boolean WithTokenHeader) throws WeiboException {
        log("Request:");
        log("POST" + url);
        PostMethod postMethod = new PostMethod(url);
        for (int i = 0; i < params.length; i++) {
            postMethod.addParameter(params[i].getName(), params[i].getValue());
        }
        HttpMethodParams param = postMethod.getParams();
        param.setContentCharset("UTF-8");
        if (WithTokenHeader) {
            return httpRequest(postMethod);
        } else {
            return httpRequest(postMethod, WithTokenHeader);
        }
    }

    /**
     * 支持multipart方式上传图片
     * 
     */
    public Response multPartURL(String url, PostParameter[] params,
            ImageItem item) throws WeiboException {
        PostMethod postMethod = new PostMethod(url);
        try {
            Part[] parts = null;
            if (params == null) {
                parts = new Part[1];
            } else {
                parts = new Part[params.length + 1];
            }
            if (params != null) {
                int i = 0;
                for (PostParameter entry : params) {
                    parts[i++] = new StringPart(entry.getName(),
                            (String) entry.getValue());
                }
                parts[parts.length - 1] = new ByteArrayPart(item.getContent(),
                        item.getName(), item.getContentType());
            }
            postMethod.setRequestEntity(new MultipartRequestEntity(parts,
                    postMethod.getParams()));
            return httpRequest(postMethod);

        } catch (Exception ex) {
            throw new WeiboException(ex.getMessage(), ex, -1);
        }
    }

    public Response multPartURL(String fileParamName, String url,
            PostParameter[] params, File file, boolean authenticated)
            throws WeiboException {
        PostMethod postMethod = new PostMethod(url);
        try {
            Part[] parts = null;
            if (params == null) {
                parts = new Part[1];
            } else {
                parts = new Part[params.length + 1];
            }
            if (params != null) {
                int i = 0;
                for (PostParameter entry : params) {
                    parts[i++] = new StringPart(entry.getName(),
                            (String) entry.getValue());
                }
            }
            FilePart filePart = new FilePart(fileParamName, file.getName(),
                    file, new MimetypesFileTypeMap().getContentType(file),
                    "UTF-8");
            filePart.setTransferEncoding("binary");
            parts[parts.length - 1] = filePart;

            postMethod.setRequestEntity(new MultipartRequestEntity(parts,
                    postMethod.getParams()));
            return httpRequest(postMethod);
        } catch (Exception ex) {
            throw new WeiboException(ex.getMessage(), ex, -1);
        }
    }

    public Response httpRequest(HttpMethod method) throws WeiboException {
        return httpRequest(method, true);
    }

    public Response httpRequest(HttpMethod method, Boolean WithTokenHeader)
            throws WeiboException {
        InetAddress ipaddr;
        int responseCode = -1;
        try {
            ipaddr = InetAddress.getLocalHost();
            List<Header> headers = new ArrayList<Header>();
            if (WithTokenHeader) {
                if (token == null) {
                    throw new IllegalStateException("Oauth2 token is not set!");
                }
                headers.add(new Header("Authorization", "OAuth2 " + token));
                headers.add(new Header("API-RemoteIP", ipaddr.getHostAddress()));
                client.getHostConfiguration().getParams()
                        .setParameter("http.default-headers", headers);
                for (Header hd : headers) {
                    log(hd.getName() + ": " + hd.getValue());
                }
            }

            method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
                    new DefaultHttpMethodRetryHandler(3, false));
            client.executeMethod(method);
            Header[] resHeader = method.getResponseHeaders();
            responseCode = method.getStatusCode();
            log("Response:");
            log("https StatusCode:" + String.valueOf(responseCode));

            for (Header header : resHeader) {
                log(header.getName() + ":" + header.getValue());
            }
            Response response = new Response();
            response.setResponseAsString(method.getResponseBodyAsString());
            log(response.toString() + "\n");

            if (responseCode != OK)

            {
                try {
                    throw new WeiboException(getCause(responseCode),
                            response.asJSONObject(), method.getStatusCode());
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
            return response;

        } catch (IOException ioe) {
            throw new WeiboException(ioe.getMessage(), ioe, responseCode);
        } finally {
            method.releaseConnection();
        }

    }

    /*
     * 对parameters进行encode处理
     */
    public static String encodeParameters(PostParameter[] postParams) {
        StringBuffer buf = new StringBuffer();
        for (int j = 0; j < postParams.length; j++) {
            if (j != 0) {
                buf.append("&");
            }
            try {
                buf.append(URLEncoder.encode(postParams[j].getName(), "UTF-8"))
                        .append("=")
                        .append(URLEncoder.encode(postParams[j].getValue(),
                                "UTF-8"));
            } catch (java.io.UnsupportedEncodingException neverHappen) {
            }
        }
        return buf.toString();
    }

    private static class ByteArrayPart extends PartBase {
        private byte[] mData;
        private String mName;

        public ByteArrayPart(byte[] data, String name, String type)
                throws IOException {
            super(name, type, "UTF-8", "binary");
            mName = name;
            mData = data;
        }

        protected void sendData(OutputStream out) throws IOException {
            out.write(mData);
        }

        protected long lengthOfData() throws IOException {
            return mData.length;
        }

        protected void sendDispositionHeader(OutputStream out)
                throws IOException {
            super.sendDispositionHeader(out);
            StringBuilder buf = new StringBuilder();
            buf.append("; filename=\"").append(mName).append("\"");
            out.write(buf.toString().getBytes());
        }
    }

    private static String getCause(int statusCode) {
        String cause = null;
        switch (statusCode) {
        case NOT_MODIFIED:
            break;
        case BAD_REQUEST:
            cause = "The request was invalid.  An accompanying error message will explain why. This is the status code will be returned during rate limiting.";
            break;
        case NOT_AUTHORIZED:
            cause = "Authentication credentials were missing or incorrect.";
            break;
        case FORBIDDEN:
            cause = "The request is understood, but it has been refused.  An accompanying error message will explain why.";
            break;
        case NOT_FOUND:
            cause = "The URI requested is invalid or the resource requested, such as a user, does not exists.";
            break;
        case NOT_ACCEPTABLE:
            cause = "Returned by the Search API when an invalid format is specified in the request.";
            break;
        case INTERNAL_SERVER_ERROR:
            cause = "Something is broken.  Please post to the group so the Weibo team can investigate.";
            break;
        case BAD_GATEWAY:
            cause = "Weibo is down or being upgraded.";
            break;
        case SERVICE_UNAVAILABLE:
            cause = "Service Unavailable: The Weibo servers are up, but overloaded with requests. Try again later. The search and trend methods use this to indicate when you are being rate limited.";
            break;
        default:
            cause = "";
        }
        return statusCode + ":" + cause;
    }

    public String getToken() {
        return token;
    }

}

ImageItem.java

package weibo4j.http;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Iterator;

import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.MemoryCacheImageInputStream;

import weibo4j.model.Constants;
import weibo4j.model.WeiboException;

import com.sun.imageio.plugins.bmp.BMPImageReader;
import com.sun.imageio.plugins.gif.GIFImageReader;
import com.sun.imageio.plugins.jpeg.JPEGImageReader;
import com.sun.imageio.plugins.png.PNGImageReader;

/**
 * 临时存储上传图片的内容,格式,文件信息等
 * 
 */
public class ImageItem {
    private byte[] content;
    private String name;
    private String contentType;

    public ImageItem(byte[] content) throws WeiboException {
        this(Constants.UPLOAD_MODE, content);
    }

    public ImageItem(String name, byte[] content) throws WeiboException {
        String imgtype = null;
        try {
            imgtype = getContentType(content);
        } catch (IOException e) {
            throw new WeiboException(e);
        }

        if (imgtype != null
                && (imgtype.equalsIgnoreCase("image/gif")
                        || imgtype.equalsIgnoreCase("image/png") || imgtype
                            .equalsIgnoreCase("image/jpeg"))) {
            this.content = content;
            this.name = name;
            this.contentType = imgtype;
        } else {
            throw new WeiboException(
                    "Unsupported image type, Only Suport JPG ,GIF,PNG!");
        }
    }

    public byte[] getContent() {
        return content;
    }

    public String getName() {
        return name;
    }

    public String getContentType() {
        return contentType;
    }

    public static String getContentType(byte[] mapObj) throws IOException {

        String type = "";
        ByteArrayInputStream bais = null;
        MemoryCacheImageInputStream mcis = null;
        try {
            bais = new ByteArrayInputStream(mapObj);
            mcis = new MemoryCacheImageInputStream(bais);
            Iterator itr = ImageIO.getImageReaders(mcis);
            while (itr.hasNext()) {
                ImageReader reader = (ImageReader) itr.next();
                if (reader instanceof GIFImageReader) {
                    type = "image/gif";
                } else if (reader instanceof JPEGImageReader) {
                    type = "image/jpeg";
                } else if (reader instanceof PNGImageReader) {
                    type = "image/png";
                } else if (reader instanceof BMPImageReader) {
                    type = "application/x-bmp";
                }
            }
        } finally {
            if (bais != null) {
                try {
                    bais.close();
                } catch (IOException ioe) {

                }
            }
            if (mcis != null) {
                try {
                    mcis.close();
                } catch (IOException ioe) {

                }
            }
        }
        return type;
    }
}

Response.java


package weibo4j.http;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;

import weibo4j.model.Configuration;
import weibo4j.model.WeiboException;
import weibo4j.org.json.JSONArray;
import weibo4j.org.json.JSONException;
import weibo4j.org.json.JSONObject;

/**
 * A data class representing HTTP Response
 * 
 * @author Yusuke Yamamoto - yusuke at mac.com
 */
public class Response {
    private final static boolean DEBUG = Configuration.getDebug();
    static Logger log = Logger.getLogger(Response.class.getName());

    private static ThreadLocal<DocumentBuilder> builders = new ThreadLocal<DocumentBuilder>() {
        @Override
        protected DocumentBuilder initialValue() {
            try {
                return DocumentBuilderFactory.newInstance()
                        .newDocumentBuilder();
            } catch (ParserConfigurationException ex) {
                throw new ExceptionInInitializerError(ex);
            }
        }
    };

    private int statusCode;
    private Document responseAsDocument = null;
    private String responseAsString = null;
    private InputStream is;
    private HttpURLConnection con;
    private boolean streamConsumed = false;

    public Response() {

    }

    public Response(HttpURLConnection con) throws IOException {
        this.con = con;
        this.statusCode = con.getResponseCode();
        if (null == (is = con.getErrorStream())) {
            is = con.getInputStream();
        }
        if (null != is && "gzip".equals(con.getContentEncoding())) {
            // the response is gzipped
            is = new GZIPInputStream(is);
        }
    }

    // for test purpose
    /* package */Response(String content) {
        this.responseAsString = content;
    }

    public int getStatusCode() {
        return statusCode;
    }

    public String getResponseHeader(String name) {
        if (con != null)
            return con.getHeaderField(name);
        else
            return null;
    }

    /**
     * Returns the response stream.<br>
     * This method cannot be called after calling asString() or asDcoument()<br>
     * It is suggested to call disconnect() after consuming the stream.
     * 
     * Disconnects the internal HttpURLConnection silently.
     * 
     * @return response body stream
     * @throws WeiboException
     * @see #disconnect()
     */
    public InputStream asStream() {
        if (streamConsumed) {
            throw new IllegalStateException("Stream has already been consumed.");
        }
        return is;
    }

    /**
     * Returns the response body as string.<br>
     * Disconnects the internal HttpURLConnection silently.
     * 
     * @return response body
     * @throws WeiboException
     */
    public String asString() throws WeiboException {
        if (null == responseAsString) {
            BufferedReader br;
            try {
                InputStream stream = asStream();
                if (null == stream) {
                    return null;
                }
                br = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
                StringBuffer buf = new StringBuffer();
                String line;
                while (null != (line = br.readLine())) {
                    buf.append(line).append("\n");
                }
                this.responseAsString = buf.toString();
                if (Configuration.isDalvik()) {
                    this.responseAsString = unescape(responseAsString);
                }
                log(responseAsString);
                stream.close();
                con.disconnect();
                streamConsumed = true;
            } catch (NullPointerException npe) {
                // don't remember in which case npe can be thrown
                throw new WeiboException(npe.getMessage(), npe);
            } catch (IOException ioe) {
                throw new WeiboException(ioe.getMessage(), ioe);
            }
        }
        return responseAsString;
    }

    /**
     * Returns the response body as org.w3c.dom.Document.<br>
     * Disconnects the internal HttpURLConnection silently.
     * 
     * @return response body as org.w3c.dom.Document
     * @throws WeiboException
     */
    public Document asDocument() throws WeiboException {
        if (null == responseAsDocument) {
            try {
                // it should be faster to read the inputstream directly.
                // but makes it difficult to troubleshoot
                this.responseAsDocument = builders.get().parse(
                        new ByteArrayInputStream(asString().getBytes("UTF-8")));
            } catch (SAXException saxe) {
                throw new WeiboException(
                        "The response body was not well-formed:\n"
                                + responseAsString, saxe);
            } catch (IOException ioe) {
                throw new WeiboException(
                        "There's something with the connection.", ioe);
            }
        }
        return responseAsDocument;
    }

    /**
     * Returns the response body as sinat4j.org.json.JSONObject.<br>
     * Disconnects the internal HttpURLConnection silently.
     * 
     * @return response body as sinat4j.org.json.JSONObject
     * @throws WeiboException
     */
    public JSONObject asJSONObject() throws WeiboException {
        try {
            return new JSONObject(asString());
        } catch (JSONException jsone) {
            throw new WeiboException(jsone.getMessage() + ":"
                    + this.responseAsString, jsone);
        }
    }

    /**
     * Returns the response body as sinat4j.org.json.JSONArray.<br>
     * Disconnects the internal HttpURLConnection silently.
     * 
     * @return response body as sinat4j.org.json.JSONArray
     * @throws WeiboException
     */
    public JSONArray asJSONArray() throws WeiboException {
        try {
            return new JSONArray(asString());
        } catch (Exception jsone) {
            throw new WeiboException(jsone.getMessage() + ":"
                    + this.responseAsString, jsone);
        }
    }

    public InputStreamReader asReader() {
        try {
            return new InputStreamReader(is, "UTF-8");
        } catch (java.io.UnsupportedEncodingException uee) {
            return new InputStreamReader(is);
        }
    }

    public void disconnect() {
        con.disconnect();
    }

    private static Pattern escaped = Pattern.compile("&#([0-9]{3,5});");

    /**
     * Unescape UTF-8 escaped characters to string.
     * 
     * @author pengjianq...@gmail.com
     * 
     * @param original
     *            The string to be unescaped.
     * @return The unescaped string
     */
    public static String unescape(String original) {
        Matcher mm = escaped.matcher(original);
        StringBuffer unescaped = new StringBuffer();
        while (mm.find()) {
            mm.appendReplacement(unescaped, Character.toString((char) Integer
                    .parseInt(mm.group(1), 10)));
        }
        mm.appendTail(unescaped);
        return unescaped.toString();
    }

    @Override
    public String toString() {
        if (null != responseAsString) {
            return responseAsString;
        }
        return "Response{" + "statusCode=" + statusCode + ", response="
                + responseAsDocument + ", responseString='" + responseAsString
                + '\'' + ", is=" + is + ", con=" + con + '}';
    }

    private void log(String message) {
        if (DEBUG) {
            log.debug("[" + new java.util.Date() + "]" + message);
        }
    }

    private void log(String message, String message2) {
        if (DEBUG) {
            log(message + message2);
        }
    }

    public String getResponseAsString() {
        return responseAsString;
    }

    public void setResponseAsString(String responseAsString) {
        this.responseAsString = responseAsString;
    }

    public void setStatusCode(int statusCode) {
        this.statusCode = statusCode;
    }

}

weibo4j.model包

ApiRateLimits.java

package weibo4j.model;

import weibo4j.org.json.JSONException;
import weibo4j.org.json.JSONObject;

public class ApiRateLimits implements java.io.Serializable {

    private static final long serialVersionUID = 8550645887134692311L;
    private String api; // 接口
    private int limit; // 接口限制
    private String limitTimeUnit; // 限制单元
    private long remainingHits; // 剩余调用次数

    ApiRateLimits(JSONObject json) throws WeiboException {
        try {
            api = json.getString("api");
            limit = json.getInt("limit");
            limitTimeUnit = json.getString("limit_time_unit");
            remainingHits = json.getLong("remaining_hits");
        } catch (JSONException jsone) {
            throw new WeiboException(
                    jsone.getMessage() + ":" + json.toString(), jsone);
        }
    }

    public String getApi() {
        return api;
    }

    public void setApi(String api) {
        this.api = api;
    }

    public int getLimit() {
        return limit;
    }

    public void setLimit(int limit) {
        this.limit = limit;
    }

    public String getLimitTimeUnit() {
        return limitTimeUnit;
    }

    public void setLimitTimeUnit(String limitTimeUnit) {
        this.limitTimeUnit = limitTimeUnit;
    }

    public long getRemainingHits() {
        return remainingHits;
    }

    public void setRemainingHits(long remainingHits) {
        this.remainingHits = remainingHits;
    }

    @Override
    public String toString() {
        return "api_rate_limits [api=" + api + ", limit=" + limit
                + ", limitTimeUnit=" + limitTimeUnit + ", remainingHits="
                + remainingHits + "]";
    }

}

Configuration.java


package weibo4j.model;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.AccessControlException;
import java.util.Properties;

public class Configuration {
    private static Properties defaultProperty;

    static {
        init();
    }

    /* package */static void init() {
        defaultProperty = new Properties();
        defaultProperty.setProperty("weibo4j.debug", "true");
        // defaultProperty.setProperty("weibo4j.source", Weibo.CONSUMER_KEY);
        // defaultProperty.setProperty("weibo4j.clientVersion","");
        defaultProperty.setProperty("weibo4j.clientURL",
                "http://open.t.sina.com.cn/-{weibo4j.clientVersion}.xml");
        defaultProperty.setProperty("weibo4j.http.userAgent",
                "weibo4j http://open.t.sina.com.cn/ /{weibo4j.clientVersion}");
        // defaultProperty.setProperty("weibo4j.user","");
        // defaultProperty.setProperty("weibo4j.password","");
        defaultProperty.setProperty("weibo4j.http.useSSL", "false");
        // defaultProperty.setProperty("weibo4j.http.proxyHost","");
        defaultProperty.setProperty("weibo4j.http.proxyHost.fallback",
                "http.proxyHost");
        // defaultProperty.setProperty("weibo4j.http.proxyUser","");
        // defaultProperty.setProperty("weibo4j.http.proxyPassword","");
        // defaultProperty.setProperty("weibo4j.http.proxyPort","");
        defaultProperty.setProperty("weibo4j.http.proxyPort.fallback",
                "http.proxyPort");
        defaultProperty.setProperty("weibo4j.http.connectionTimeout", "20000");
        defaultProperty.setProperty("weibo4j.http.readTimeout", "120000");
        defaultProperty.setProperty("weibo4j.http.retryCount", "3");
        defaultProperty.setProperty("weibo4j.http.retryIntervalSecs", "10");
        // defaultProperty.setProperty("weibo4j.oauth.consumerKey","");
        // defaultProperty.setProperty("weibo4j.oauth.consumerSecret","");
        defaultProperty.setProperty("weibo4j.async.numThreads", "1");
        defaultProperty.setProperty("weibo4j.clientVersion",
                Version.getVersion());
        try {
            // Android platform should have dalvik.system.VMRuntime in the
            // classpath.
            // @see
            // http://developer.android.com/reference/dalvik/system/VMRuntime.html
            Class.forName("dalvik.system.VMRuntime");
            defaultProperty.setProperty("weibo4j.dalvik", "true");
        } catch (ClassNotFoundException cnfe) {
            defaultProperty.setProperty("weibo4j.dalvik", "false");
        }
        DALVIK = getBoolean("weibo4j.dalvik");
        String t4jProps = "weibo4j.properties";
        boolean loaded = loadProperties(defaultProperty, "."
                + File.separatorChar + t4jProps)
                || loadProperties(
                        defaultProperty,
                        Configuration.class.getResourceAsStream("/WEB-INF/"
                                + t4jProps))
                || loadProperties(defaultProperty,
                        Configuration.class.getResourceAsStream("/" + t4jProps));
    }

    private static boolean loadProperties(Properties props, String path) {
        try {
            File file = new File(path);
            if (file.exists() && file.isFile()) {
                props.load(new FileInputStream(file));
                return true;
            }
        } catch (Exception ignore) {
        }
        return false;
    }

    private static boolean loadProperties(Properties props, InputStream is) {
        try {
            props.load(is);
            return true;
        } catch (Exception ignore) {
        }
        return false;
    }

    private static boolean DALVIK;

    public static boolean isDalvik() {
        return DALVIK;
    }

    public static boolean useSSL() {
        return getBoolean("weibo4j.http.useSSL");
    }

    public static String getScheme() {
        return useSSL() ? "https://" : "http://";
    }

    public static String getCilentVersion() {
        return getProperty("weibo4j.clientVersion");
    }

    public static String getCilentVersion(String clientVersion) {
        return getProperty("weibo4j.clientVersion", clientVersion);
    }

    public static String getSource() {
        return getProperty("weibo4j.source");
    }

    public static String getSource(String source) {
        return getProperty("weibo4j.source", source);
    }

    public static String getProxyHost() {
        return getProperty("weibo4j.http.proxyHost");
    }

    public static String getProxyHost(String proxyHost) {
        return getProperty("weibo4j.http.proxyHost", proxyHost);
    }

    public static String getProxyUser() {
        return getProperty("weibo4j.http.proxyUser");
    }

    public static String getProxyUser(String user) {
        return getProperty("weibo4j.http.proxyUser", user);
    }

    public static String getClientURL() {
        return getProperty("weibo4j.clientURL");
    }

    public static String getClientURL(String clientURL) {
        return getProperty("weibo4j.clientURL", clientURL);
    }

    public static String getProxyPassword() {
        return getProperty("weibo4j.http.proxyPassword");
    }

    public static String getProxyPassword(String password) {
        return getProperty("weibo4j.http.proxyPassword", password);
    }

    public static int getProxyPort() {
        return getIntProperty("weibo4j.http.proxyPort");
    }

    public static int getProxyPort(int port) {
        return getIntProperty("weibo4j.http.proxyPort", port);
    }

    public static int getConnectionTimeout() {
        return getIntProperty("weibo4j.http.connectionTimeout");
    }

    public static int getConnectionTimeout(int connectionTimeout) {
        return getIntProperty("weibo4j.http.connectionTimeout",
                connectionTimeout);
    }

    public static int getReadTimeout() {
        return getIntProperty("weibo4j.http.readTimeout");
    }

    public static int getReadTimeout(int readTimeout) {
        return getIntProperty("weibo4j.http.readTimeout", readTimeout);
    }

    public static int getRetryCount() {
        return getIntProperty("weibo4j.http.retryCount");
    }

    public static int getRetryCount(int retryCount) {
        return getIntProperty("weibo4j.http.retryCount", retryCount);
    }

    public static int getRetryIntervalSecs() {
        return getIntProperty("weibo4j.http.retryIntervalSecs");
    }

    public static int getRetryIntervalSecs(int retryIntervalSecs) {
        return getIntProperty("weibo4j.http.retryIntervalSecs",
                retryIntervalSecs);
    }

    public static String getUser() {
        return getProperty("weibo4j.user");
    }

    public static String getUser(String userId) {
        return getProperty("weibo4j.user", userId);
    }

    public static String getPassword() {
        return getProperty("weibo4j.password");
    }

    public static String getPassword(String password) {
        return getProperty("weibo4j.password", password);
    }

    public static String getUserAgent() {
        return getProperty("weibo4j.http.userAgent");
    }

    public static String getUserAgent(String userAgent) {
        return getProperty("weibo4j.http.userAgent", userAgent);
    }

    public static String getOAuthConsumerKey() {
        return getProperty("weibo4j.oauth.consumerKey");
    }

    public static String getOAuthConsumerKey(String consumerKey) {
        return getProperty("weibo4j.oauth.consumerKey", consumerKey);
    }

    public static String getOAuthConsumerSecret() {
        return getProperty("weibo4j.oauth.consumerSecret");
    }

    public static String getOAuthConsumerSecret(String consumerSecret) {
        return getProperty("weibo4j.oauth.consumerSecret", consumerSecret);
    }

    public static boolean getBoolean(String name) {
        String value = getProperty(name);
        return Boolean.valueOf(value);
    }

    public static int getIntProperty(String name) {
        String value = getProperty(name);
        try {
            return Integer.parseInt(value);
        } catch (NumberFormatException nfe) {
            return -1;
        }
    }

    public static int getIntProperty(String name, int fallbackValue) {
        String value = getProperty(name, String.valueOf(fallbackValue));
        try {
            return Integer.parseInt(value);
        } catch (NumberFormatException nfe) {
            return -1;
        }
    }

    public static long getLongProperty(String name) {
        String value = getProperty(name);
        try {
            return Long.parseLong(value);
        } catch (NumberFormatException nfe) {
            return -1;
        }
    }

    public static String getProperty(String name) {
        return getProperty(name, null);
    }

    public static String getProperty(String name, String fallbackValue) {
        String value;
        try {
            value = System.getProperty(name, fallbackValue);
            if (null == value) {
                value = defaultProperty.getProperty(name);
            }
            if (null == value) {
                String fallback = defaultProperty.getProperty(name
                        + ".fallback");
                if (null != fallback) {
                    value = System.getProperty(fallback);
                }
            }
        } catch (AccessControlException ace) {
            // Unsigned applet cannot access System properties
            value = fallbackValue;
        }
        return replace(value);
    }

    private static String replace(String value) {
        if (null == value) {
            return value;
        }
        String newValue = value;
        int openBrace = 0;
        if (-1 != (openBrace = value.indexOf("{", openBrace))) {
            int closeBrace = value.indexOf("}", openBrace);
            if (closeBrace > (openBrace + 1)) {
                String name = value.substring(openBrace + 1, closeBrace);
                if (name.length() > 0) {
                    newValue = value.substring(0, openBrace)
                            + getProperty(name)
                            + value.substring(closeBrace + 1);

                }
            }
        }
        if (newValue.equals(value)) {
            return value;
        } else {
            return replace(newValue);
        }
    }

    public static int getNumberOfAsyncThreads() {
        return getIntProperty("weibo4j.async.numThreads");
    }

    public static boolean getDebug() {
        return getBoolean("weibo4j.debug");

    }
}

Constants.java

package weibo4j.model;

public class Constants {
    public static final String X_AUTH_MODE = "client_auth";
    public static final String UPLOAD_MODE = "pic";
}

MySSLSocketFactory.java

package weibo4j.model;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.SocketFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.commons.httpclient.ConnectTimeoutException;
import org.apache.commons.httpclient.params.HttpConnectionParams;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;


public class MySSLSocketFactory implements ProtocolSocketFactory {
    private SSLContext sslcontext = null;

    private SSLContext createSSLContext() {
        SSLContext sslcontext = null;
        try {
            sslcontext = SSLContext.getInstance("SSL");
            sslcontext.init(null,
                    new TrustManager[] { new TrustAnyTrustManager() },
                    new java.security.SecureRandom());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }
        return sslcontext;
    }

    private SSLContext getSSLContext() {
        if (this.sslcontext == null) {
            this.sslcontext = createSSLContext();
        }
        return this.sslcontext;
    }

    public Socket createSocket(Socket socket, String host, int port,
            boolean autoClose) throws IOException, UnknownHostException {
        return getSSLContext().getSocketFactory().createSocket(socket, host,
                port, autoClose);
    }

    public Socket createSocket(String host, int port) throws IOException,
            UnknownHostException {
        return getSSLContext().getSocketFactory().createSocket(host, port);
    }

    public Socket createSocket(String host, int port, InetAddress clientHost,
            int clientPort) throws IOException, UnknownHostException {
        return getSSLContext().getSocketFactory().createSocket(host, port,
                clientHost, clientPort);
    }

    public Socket createSocket(String host, int port, InetAddress localAddress,
            int localPort, HttpConnectionParams params) throws IOException,
            UnknownHostException, ConnectTimeoutException {
        if (params == null) {
            throw new IllegalArgumentException("Parameters may not be null");
        }
        int timeout = params.getConnectionTimeout();
        SocketFactory socketfactory = getSSLContext().getSocketFactory();
        if (timeout == 0) {
            return socketfactory.createSocket(host, port, localAddress,
                    localPort);
        } else {
            Socket socket = socketfactory.createSocket();
            SocketAddress localaddr = new InetSocketAddress(localAddress,
                    localPort);
            SocketAddress remoteaddr = new InetSocketAddress(host, port);
            socket.bind(localaddr);
            socket.connect(remoteaddr, timeout);
            return socket;
        }
    }

    private static class TrustAnyTrustManager implements X509TrustManager {
        public void checkClientTrusted(X509Certificate[] chain, String authType)
                throws CertificateException {
        }

        public void checkServerTrusted(X509Certificate[] chain, String authType)
                throws CertificateException {
        }

        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[] {};
        }
    }
}

Paging.java


package weibo4j.model;

public class Paging implements java.io.Serializable {
    private static final long serialVersionUID = -3285857427993796670L;

    private int page = -1; // 页码。注意:最多返回200条分页内容。
    private int count = -1; // 指定每页返回的记录条数。
    private long sinceId = -1; // 若指定此参数,则只返回ID比since_id大(即比since_id发表时间晚的)的微博消息。
    private long maxId = -1; // 若指定此参数,则返回ID小于或等于max_id的微博消息

    public Paging() {
    }

    public Paging(int page) {
        setPage(page);
    }

    public Paging(long sinceId) {
        setSinceId(sinceId);
    }

    public Paging(int page, int count) {
        this(page);
        setCount(count);
    }

    public Paging(int page, long sinceId) {
        this(page);
        setSinceId(sinceId);
    }

    public Paging(int page, int count, long sinceId) {
        this(page, count);
        setSinceId(sinceId);
    }

    public Paging(int page, int count, long sinceId, long maxId) {
        this(page, count, sinceId);
        setMaxId(maxId);
    }

    public int getPage() {
        return page;
    }

    public void setPage(int page) {
        if (page < 1) {
            throw new IllegalArgumentException(
                    "page should be positive integer. passed:" + page);
        }
        this.page = page;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        if (count < 1) {
            throw new IllegalArgumentException(
                    "count should be positive integer. passed:" + count);
        }
        this.count = count;
    }

    public Paging count(int count) {
        setCount(count);
        return this;
    }

    public long getSinceId() {
        return sinceId;
    }

    public void setSinceId(int sinceId) {
        if (sinceId < 1) {
            throw new IllegalArgumentException(
                    "since_id should be positive integer. passed:" + sinceId);
        }
        this.sinceId = sinceId;
    }

    public Paging sinceId(int sinceId) {
        setSinceId(sinceId);
        return this;
    }

    public void setSinceId(long sinceId) {
        if (sinceId < 1) {
            throw new IllegalArgumentException(
                    "since_id should be positive integer. passed:" + sinceId);
        }
        this.sinceId = sinceId;
    }

    public Paging sinceId(long sinceId) {
        setSinceId(sinceId);
        return this;
    }

    public long getMaxId() {
        return maxId;
    }

    public void setMaxId(long maxId) {
        if (maxId < 1) {
            throw new IllegalArgumentException(
                    "max_id should be positive integer. passed:" + maxId);
        }
        this.maxId = maxId;
    }

    public Paging maxId(long maxId) {
        setMaxId(maxId);
        return this;
    }
}

PostParameter.java


package weibo4j.model;

import java.io.File;
import java.net.URLEncoder;
import java.util.List;


public class PostParameter implements java.io.Serializable {
    String name;
    String value;
    private File file = null;

    private static final long serialVersionUID = -8708108746980739212L;

    public PostParameter(String name, String value) {
        this.name = name;
        this.value = value;
    }

    public PostParameter(String name, double value) {
        this.name = name;
        this.value = String.valueOf(value);
    }

    public PostParameter(String name, int value) {
        this.name = name;
        this.value = String.valueOf(value);
    }

    public PostParameter(String name, File file) {
        this.name = name;
        this.file = file;
    }

    public String getName() {
        return name;
    }

    public String getValue() {
        return value;
    }

    public File getFile() {
        return file;
    }

    public boolean isFile() {
        return null != file;
    }

    private static final String JPEG = "image/jpeg";
    private static final String GIF = "image/gif";
    private static final String PNG = "image/png";
    private static final String OCTET = "application/octet-stream";

    /**
     * 
     * @return content-type
     */
    public String getContentType() {
        if (!isFile()) {
            throw new IllegalStateException("not a file");
        }
        String contentType;
        String extensions = file.getName();
        int index = extensions.lastIndexOf(".");
        if (-1 == index) {
            // no extension
            contentType = OCTET;
        } else {
            extensions = extensions.substring(extensions.lastIndexOf(".") + 1)
                    .toLowerCase();
            if (extensions.length() == 3) {
                if ("gif".equals(extensions)) {
                    contentType = GIF;
                } else if ("png".equals(extensions)) {
                    contentType = PNG;
                } else if ("jpg".equals(extensions)) {
                    contentType = JPEG;
                } else {
                    contentType = OCTET;
                }
            } else if (extensions.length() == 4) {
                if ("jpeg".equals(extensions)) {
                    contentType = JPEG;
                } else {
                    contentType = OCTET;
                }
            } else {
                contentType = OCTET;
            }
        }
        return contentType;
    }

    public static boolean containsFile(PostParameter[] params) {
        boolean containsFile = false;
        if (null == params) {
            return false;
        }
        for (PostParameter param : params) {
            if (param.isFile()) {
                containsFile = true;
                break;
            }
        }
        return containsFile;
    }

    /* package */static boolean containsFile(List<PostParameter> params) {
        boolean containsFile = false;
        for (PostParameter param : params) {
            if (param.isFile()) {
                containsFile = true;
                break;
            }
        }
        return containsFile;
    }

    public static PostParameter[] getParameterArray(String name, String value) {
        return new PostParameter[] { new PostParameter(name, value) };
    }

    public static PostParameter[] getParameterArray(String name, int value) {
        return getParameterArray(name, String.valueOf(value));
    }

    public static PostParameter[] getParameterArray(String name1,
            String value1, String name2, String value2) {
        return new PostParameter[] { new PostParameter(name1, value1),
                new PostParameter(name2, value2) };
    }

    public static PostParameter[] getParameterArray(String name1, int value1,
            String name2, int value2) {
        return getParameterArray(name1, String.valueOf(value1), name2,
                String.valueOf(value2));
    }

    @Override
    public int hashCode() {
        int result = name.hashCode();
        result = 31 * result + value.hashCode();
        result = 31 * result + (file != null ? file.hashCode() : 0);
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (null == obj) {
            return false;
        }
        if (this == obj) {
            return true;
        }
        if (obj instanceof PostParameter) {
            PostParameter that = (PostParameter) obj;

            if (file != null ? !file.equals(that.file) : that.file != null)
                return false;

            return this.name.equals(that.name) && this.value.equals(that.value);
        }
        return false;
    }

    @Override
    public String toString() {
        return "PostParameter{" + "name='" + name + '\'' + ", value='" + value
                + '\'' + ", file=" + file + '}';
    }

    public int compareTo(Object o) {
        int compared;
        PostParameter that = (PostParameter) o;
        compared = name.compareTo(that.name);
        if (0 == compared) {
            compared = value.compareTo(that.value);
        }
        return compared;
    }

    public static String encodeParameters(PostParameter[] httpParams) {
        if (null == httpParams) {
            return "";
        }
        StringBuffer buf = new StringBuffer();
        for (int j = 0; j < httpParams.length; j++) {
            if (httpParams[j].isFile()) {
                throw new IllegalArgumentException("parameter ["
                        + httpParams[j].name + "]should be text");
            }
            if (j != 0) {
                buf.append("&");
            }
            try {
                buf.append(URLEncoder.encode(httpParams[j].name, "UTF-8"))
                        .append("=")
                        .append(URLEncoder.encode(httpParams[j].value, "UTF-8"));
            } catch (java.io.UnsupportedEncodingException neverHappen) {
            }
        }
        return buf.toString();

    }

}

Source.java

package weibo4j.model;

public class Source implements java.io.Serializable {

    private static final long serialVersionUID = -8972443458374235866L;
    private String url; // 来源连接
    private String relationShip;
    private String name; // 来源文案名称

    public Source(String str) {
        super();
        String[] source = str.split("\"", 5);
        url = source[1];
        relationShip = source[3];
        name = source[4].replace(">", "").replace("</a", "");
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getRelationship() {
        return relationShip;
    }

    public void setRelationship(String relationShip) {
        this.relationShip = relationShip;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Source [url=" + url + ", relationShip=" + relationShip
                + ", name=" + name + "]";
    }

}

Status.java

package weibo4j.model;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import weibo4j.http.Response;
import weibo4j.org.json.JSONArray;
import weibo4j.org.json.JSONException;
import weibo4j.org.json.JSONObject;

public class Status extends WeiboResponse implements java.io.Serializable {

    private static final long serialVersionUID = -8795691786466526420L;

    private User user = null; // 作者信息
    private Date createdAt; // status创建时间
    private String id; // status id
    private String mid; // 微博MID
    private long idstr; // 保留字段,请勿使用
    private String text; // 微博内容
    private Source source; // 微博来源
    private boolean favorited; // 是否已收藏
    private boolean truncated;
    private long inReplyToStatusId; // 回复ID
    private long inReplyToUserId; // 回复人ID
    private String inReplyToScreenName; // 回复人昵称
    private String thumbnailPic; // 微博内容中的图片的缩略地址
    private String bmiddlePic; // 中型图片
    private String originalPic; // 原始图片
    private Status retweetedStatus = null; // 转发的博文,内容为status,如果不是转发,则没有此字段
    private String geo; // 地理信息,保存经纬度,没有时不返回此字段
    private double latitude = -1; // 纬度
    private double longitude = -1; // 经度
    private int repostsCount; // 转发数
    private int commentsCount; // 评论数
    private String annotations; // 元数据,没有时不返回此字段
    private int mlevel;
    private Visible visible;

    public Status() {

    }

    public Status(Response res) throws WeiboException {
        super(res);
        JSONObject json = res.asJSONObject();
        constructJson(json);
    }

    private void constructJson(JSONObject json) throws WeiboException {
        try {
            createdAt = parseDate(json.getString("created_at"),
                    "EEE MMM dd HH:mm:ss z yyyy");
            id = json.getString("id");
            mid = json.getString("mid");
            idstr = json.getLong("idstr");
            text = json.getString("text");
            if (!json.getString("source").isEmpty()) {
                source = new Source(json.getString("source"));
            }
            inReplyToStatusId = getLong("in_reply_to_status_id", json);
            inReplyToUserId = getLong("in_reply_to_user_id", json);
            inReplyToScreenName = json.getString("in_reply_toS_screenName");
            favorited = getBoolean("favorited", json);
            truncated = getBoolean("truncated", json);
            thumbnailPic = json.getString("thumbnail_pic");
            bmiddlePic = json.getString("bmiddle_pic");
            originalPic = json.getString("original_pic");
            repostsCount = json.getInt("reposts_count");
            commentsCount = json.getInt("comments_count");
            annotations = json.getString("annotations");
            if (!json.isNull("user"))
                user = new User(json.getJSONObject("user"));
            if (!json.isNull("retweeted_status")) {
                retweetedStatus = new Status(
                        json.getJSONObject("retweeted_status"));
            }
            mlevel = json.getInt("mlevel");
            geo = json.getString("geo");
            if (geo != null && !"".equals(geo) && !"null".equals(geo)) {
                getGeoInfo(geo);
            }
            if (!json.isNull("visible")) {
                visible = new Visible(json.getJSONObject("visible"));
            }
        } catch (JSONException je) {
            throw new WeiboException(je.getMessage() + ":" + json.toString(),
                    je);
        }
    }

    private void getGeoInfo(String geo) {
        StringBuffer value = new StringBuffer();
        for (char c : geo.toCharArray()) {
            if (c > 45 && c < 58) {
                value.append(c);
            }
            if (c == 44) {
                if (value.length() > 0) {
                    latitude = Double.parseDouble(value.toString());
                    value.delete(0, value.length());
                }
            }
        }
        longitude = Double.parseDouble(value.toString());
    }

    public Status(JSONObject json) throws WeiboException, JSONException {
        constructJson(json);
    }

    public Status(String str) throws WeiboException, JSONException {
        // StatusStream uses this constructor
        super();
        JSONObject json = new JSONObject(str);
        constructJson(json);
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public long getIdstr() {
        return idstr;
    }

    public void setIdstr(long idstr) {
        this.idstr = idstr;
    }

    public Date getCreatedAt() {
        return createdAt;
    }

    public void setCreatedAt(Date createdAt) {
        this.createdAt = createdAt;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public Source getSource() {
        return source;
    }

    public void setSource(Source source) {
        this.source = source;
    }

    public boolean isFavorited() {
        return favorited;
    }

    public void setFavorited(boolean favorited) {
        this.favorited = favorited;
    }

    public long getInReplyToStatusId() {
        return inReplyToStatusId;
    }

    public void setInReplyToStatusId(long inReplyToStatusId) {
        this.inReplyToStatusId = inReplyToStatusId;
    }

    public long getInReplyToUserId() {
        return inReplyToUserId;
    }

    public void setInReplyToUserId(long inReplyToUserId) {
        this.inReplyToUserId = inReplyToUserId;
    }

    public String getInReplyToScreenName() {
        return inReplyToScreenName;
    }

    public void setInReplyToScreenName(String inReplyToScreenName) {
        this.inReplyToScreenName = inReplyToScreenName;
    }

    public String getThumbnailPic() {
        return thumbnailPic;
    }

    public void setThumbnailPic(String thumbnailPic) {
        this.thumbnailPic = thumbnailPic;
    }

    public String getBmiddlePic() {
        return bmiddlePic;
    }

    public void setBmiddlePic(String bmiddlePic) {
        this.bmiddlePic = bmiddlePic;
    }

    public String getOriginalPic() {
        return originalPic;
    }

    public void setOriginalPic(String originalPic) {
        this.originalPic = originalPic;
    }

    public Status getRetweetedStatus() {
        return retweetedStatus;
    }

    public void setRetweetedStatus(Status retweetedStatus) {
        this.retweetedStatus = retweetedStatus;
    }

    public String getGeo() {
        return geo;
    }

    public void setGeo(String geo) {
        this.geo = geo;
    }

    public double getLatitude() {
        return latitude;
    }

    public void setLatitude(double latitude) {
        this.latitude = latitude;
    }

    public double getLongitude() {
        return longitude;
    }

    public void setLongitude(double longitude) {
        this.longitude = longitude;
    }

    public int getRepostsCount() {
        return repostsCount;
    }

    public void setRepostsCount(int repostsCount) {
        this.repostsCount = repostsCount;
    }

    public int getCommentsCount() {
        return commentsCount;
    }

    public void setCommentsCount(int commentsCount) {
        this.commentsCount = commentsCount;
    }

    public String getMid() {
        return mid;
    }

    public void setMid(String mid) {
        this.mid = mid;
    }

    public String getAnnotations() {
        return annotations;
    }

    public void setAnnotations(String annotations) {
        this.annotations = annotations;
    }

    public int getMlevel() {
        return mlevel;
    }

    public void setMlevel(int mlevel) {
        this.mlevel = mlevel;
    }

    public Visible getVisible() {
        return visible;
    }

    public void setVisible(Visible visible) {
        this.visible = visible;
    }

    public boolean isTruncated() {
        return truncated;
    }

    public void setTruncated(boolean truncated) {
        this.truncated = truncated;
    }

    public static StatusWapper constructWapperStatus(Response res)
            throws WeiboException {
        JSONObject jsonStatus = res.asJSONObject(); // asJSONArray();
        JSONArray statuses = null;
        try {
            if (!jsonStatus.isNull("statuses")) {
                statuses = jsonStatus.getJSONArray("statuses");
            }
            if (!jsonStatus.isNull("reposts")) {
                statuses = jsonStatus.getJSONArray("reposts");
            }
            int size = statuses.length();
            List<Status> status = new ArrayList<Status>(size);
            for (int i = 0; i < size; i++) {
                status.add(new Status(statuses.getJSONObject(i)));
            }
            long previousCursor = jsonStatus.getLong("previous_curosr");
            long nextCursor = jsonStatus.getLong("next_cursor");
            long totalNumber = jsonStatus.getLong("total_number");
            String hasvisible = jsonStatus.getString("hasvisible");
            return new StatusWapper(status, previousCursor, nextCursor,
                    totalNumber, hasvisible);
        } catch (JSONException jsone) {
            throw new WeiboException(jsone);
        }
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((id == null) ? 0 : id.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Status other = (Status) obj;
        if (id == null) {
            if (other.id != null)
                return false;
        } else if (!id.equals(other.id))
            return false;
        return true;
    }

    @Override
    public String toString() {
        return "Status [user=" + user + ", idstr=" + idstr + ", createdAt="
                + createdAt + ", id=" + id + ", text=" + text + ", source="
                + source + ", favorited=" + favorited + ", truncated="
                + truncated + ", inReplyToStatusId=" + inReplyToStatusId
                + ", inReplyToUserId=" + inReplyToUserId
                + ", inReplyToScreenName=" + inReplyToScreenName
                + ", thumbnailPic=" + thumbnailPic + ", bmiddlePic="
                + bmiddlePic + ", originalPic=" + originalPic
                + ", retweetedStatus=" + retweetedStatus + ", geo=" + geo
                + ", latitude=" + latitude + ", longitude=" + longitude
                + ", repostsCount=" + repostsCount + ", commentsCount="
                + commentsCount + ", mid=" + mid + ", annotations="
                + annotations + ", mlevel=" + mlevel + ", visible=" + visible
                + "]";
    }

}

StatusWapper.java

package weibo4j.model;

import java.util.List;

public class StatusWapper {

    private List<Status> statuses;

    private long previousCursor;

    private long nextCursor;

    private long totalNumber;

    private String hasvisible;

    public StatusWapper(List<Status> statuses, long previousCursor,
            long nextCursor, long totalNumber, String hasvisible) {
        this.statuses = statuses;
        this.previousCursor = previousCursor;
        this.nextCursor = nextCursor;
        this.totalNumber = totalNumber;
        this.hasvisible = hasvisible;
    }

    public List<Status> getStatuses() {
        return statuses;
    }

    public void setStatuses(List<Status> statuses) {
        this.statuses = statuses;
    }

    public long getPreviousCursor() {
        return previousCursor;
    }

    public void setPreviousCursor(long previousCursor) {
        this.previousCursor = previousCursor;
    }

    public long getNextCursor() {
        return nextCursor;
    }

    public void setNextCursor(long nextCursor) {
        this.nextCursor = nextCursor;
    }

    public long getTotalNumber() {
        return totalNumber;
    }

    public void setTotalNumber(long totalNumber) {
        this.totalNumber = totalNumber;
    }

    public String getHasvisible() {
        return hasvisible;
    }

    public void setHasvisible(String hasvisible) {
        this.hasvisible = hasvisible;
    }

}

User.java


package weibo4j.model;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import weibo4j.http.Response;
import weibo4j.org.json.JSONArray;
import weibo4j.org.json.JSONException;
import weibo4j.org.json.JSONObject;

public class User extends WeiboResponse implements java.io.Serializable {

    private static final long serialVersionUID = -332738032648843482L;
    private String id; // 用户UID
    private String screenName; // 微博昵称
    private String name; // 友好显示名称,如Bill Gates,名称中间的空格正常显示(此特性暂不支持)
    private int province; // 省份编码(参考省份编码表)
    private int city; // 城市编码(参考城市编码表)
    private String location; // 地址
    private String description; // 个人描述
    private String url; // 用户博客地址
    private String profileImageUrl; // 自定义图像
    private String userDomain; // 用户个性化URL
    private String gender; // 性别,m--男,f--女,n--未知
    private int followersCount; // 粉丝数
    private int friendsCount; // 关注数
    private int statusesCount; // 微博数
    private int favouritesCount; // 收藏数
    private Date createdAt; // 创建时间
    private boolean following; // 保留字段,是否已关注(此特性暂不支持)
    private boolean verified; // 加V标示,是否微博认证用户
    private int verifiedType; // 认证类型
    private boolean allowAllActMsg; // 是否允许所有人给我发私信
    private boolean allowAllComment; // 是否允许所有人对我的微博进行评论
    private boolean followMe; // 此用户是否关注我
    private String avatarLarge; // 大头像地址
    private int onlineStatus; // 用户在线状态
    private Status status = null; // 用户最新一条微博
    private int biFollowersCount; // 互粉数
    private String remark; // 备注信息,在查询用户关系时提供此字段。
    private String lang; // 用户语言版本
    private String verifiedReason; // 认证原因
    private String weihao; // 微號
    private String statusId;

    public String getVerified_reason() {
        return verifiedReason;
    }

    public void setVerified_reason(String verifiedReason) {
        this.verifiedReason = verifiedReason;
    }

    public void setId(String id) {
        this.id = id;
    }

    public void setScreenName(String screenName) {
        this.screenName = screenName;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setProvince(int province) {
        this.province = province;
    }

    public void setCity(int city) {
        this.city = city;
    }

    public void setLocation(String location) {
        this.location = location;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public void setProfileImageUrl(String profileImageUrl) {
        this.profileImageUrl = profileImageUrl;
    }

    public void setUserDomain(String userDomain) {
        this.userDomain = userDomain;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public void setFollowersCount(int followersCount) {
        this.followersCount = followersCount;
    }

    public void setFriendsCount(int friendsCount) {
        this.friendsCount = friendsCount;
    }

    public void setStatusesCount(int statusesCount) {
        this.statusesCount = statusesCount;
    }

    public void setFavouritesCount(int favouritesCount) {
        this.favouritesCount = favouritesCount;
    }

    public void setCreatedAt(Date createdAt) {
        this.createdAt = createdAt;
    }

    public void setFollowing(boolean following) {
        this.following = following;
    }

    public void setVerified(boolean verified) {
        this.verified = verified;
    }

    public void setVerifiedType(int verifiedType) {
        this.verifiedType = verifiedType;
    }

    public void setAllowAllActMsg(boolean allowAllActMsg) {
        this.allowAllActMsg = allowAllActMsg;
    }

    public void setAllowAllComment(boolean allowAllComment) {
        this.allowAllComment = allowAllComment;
    }

    public void setFollowMe(boolean followMe) {
        this.followMe = followMe;
    }

    public void setAvatarLarge(String avatarLarge) {
        this.avatarLarge = avatarLarge;
    }

    public void setOnlineStatus(int onlineStatus) {
        this.onlineStatus = onlineStatus;
    }

    public void setStatus(Status status) {
        this.status = status;
    }

    public void setBiFollowersCount(int biFollowersCount) {
        this.biFollowersCount = biFollowersCount;
    }

    public void setRemark(String remark) {
        this.remark = remark;
    }

    public void setLang(String lang) {
        this.lang = lang;
    }

    public String getWeihao() {
        return weihao;
    }

    public void setWeihao(String weihao) {
        this.weihao = weihao;
    }

    public String getVerifiedReason() {
        return verifiedReason;
    }

    public void setVerifiedReason(String verifiedReason) {
        this.verifiedReason = verifiedReason;
    }

    public String getStatusId() {
        return statusId;
    }

    public void setStatusId(String statusId) {
        this.statusId = statusId;
    }

    public String getUrl() {
        return url;
    }

    public String getProfileImageUrl() {
        return profileImageUrl;
    }

    public int getVerifiedType() {
        return verifiedType;
    }

    public boolean isAllowAllActMsg() {
        return allowAllActMsg;
    }

    public boolean isAllowAllComment() {
        return allowAllComment;
    }

    public boolean isFollowMe() {
        return followMe;
    }

    public String getAvatarLarge() {
        return avatarLarge;
    }

    public int getOnlineStatus() {
        return onlineStatus;
    }

    public int getBiFollowersCount() {
        return biFollowersCount;
    }

    /* package */public User(JSONObject json) throws WeiboException {
        super();
        init(json);
    }

    private void init(JSONObject json) throws WeiboException {
        if (json != null) {
            try {
                id = json.getString("id");
                screenName = json.getString("screen_name");
                name = json.getString("name");
                province = json.getInt("province");
                city = json.getInt("city");
                location = json.getString("location");
                description = json.getString("description");
                url = json.getString("url");
                profileImageUrl = json.getString("profile_image_url");
                userDomain = json.getString("domain");
                gender = json.getString("gender");
                followersCount = json.getInt("followers_count");
                friendsCount = json.getInt("friends_count");
                favouritesCount = json.getInt("favourites_count");
                statusesCount = json.getInt("statuses_count");
                createdAt = parseDate(json.getString("created_at"),
                        "EEE MMM dd HH:mm:ss z yyyy");
                following = getBoolean("following", json);
                verified = getBoolean("verified", json);
                verifiedType = json.getInt("verified_type");
                verifiedReason = json.getString("verified_reason");
                allowAllActMsg = json.getBoolean("allow_all_act_msg");
                allowAllComment = json.getBoolean("allow_all_comment");
                followMe = json.getBoolean("follow_me");
                avatarLarge = json.getString("avatar_large");
                onlineStatus = json.getInt("online_status");
                statusId = json.getString("status_id");
                biFollowersCount = json.getInt("bi_followers_count");
                if (!json.getString("remark").isEmpty()) {
                    remark = json.getString("remark");
                }
                lang = json.getString("lang");
                weihao = json.getString("weihao");
                if (!json.isNull("status")) {
                    status = new Status(json.getJSONObject("status"));
                }
            } catch (JSONException jsone) {
                throw new WeiboException(jsone.getMessage() + ":"
                        + json.toString(), jsone);
            }
        }
    }

    public static String[] constructIds(Response res) throws WeiboException {
        try {
            JSONArray list = res.asJSONObject().getJSONArray("ids");
            String temp = list.toString().substring(1,
                    list.toString().length() - 1);
            String[] ids = temp.split(",");
            return ids;
        } catch (JSONException jsone) {
            throw new WeiboException(jsone.getMessage() + ":"
                    + jsone.toString(), jsone);
        }
    }

    /**
     * 
     * @param res
     * @return
     * @throws WeiboException
     */
    public static UserWapper constructWapperUsers(Response res)
            throws WeiboException {
        JSONObject jsonUsers = res.asJSONObject(); // asJSONArray();
        try {
            JSONArray user = jsonUsers.getJSONArray("users");
            int size = user.length();
            List<User> users = new ArrayList<User>(size);
            for (int i = 0; i < size; i++) {
                users.add(new User(user.getJSONObject(i)));
            }
            long previousCursor = jsonUsers.getLong("previous_curosr");
            long nextCursor = jsonUsers.getLong("next_cursor");
            long totalNumber = jsonUsers.getLong("total_number");
            String hasvisible = jsonUsers.getString("hasvisible");
            return new UserWapper(users, previousCursor, nextCursor,
                    totalNumber, hasvisible);
        } catch (JSONException jsone) {
            throw new WeiboException(jsone);
        }
    }

    /**
     * @param res
     * @return
     * @throws WeiboException
     */
    static List<User> constructResult(Response res) throws WeiboException {
        JSONArray list = res.asJSONArray();
        try {
            int size = list.length();
            List<User> users = new ArrayList<User>(size);
            for (int i = 0; i < size; i++) {
                users.add(new User(list.getJSONObject(i)));
            }
            return users;
        } catch (JSONException e) {
        }
        return null;
    }

    public String getId() {
        return id;
    }

    public String getScreenName() {
        return screenName;
    }

    public String getName() {
        return name;
    }

    public int getProvince() {
        return province;
    }

    public int getCity() {
        return city;
    }

    public String getLocation() {
        return location;
    }

    public String getDescription() {
        return description;
    }

    public URL getProfileImageURL() {
        try {
            return new URL(profileImageUrl);
        } catch (MalformedURLException ex) {
            return null;
        }
    }

    public URL getURL() {
        try {
            return new URL(url);
        } catch (MalformedURLException ex) {
            return null;
        }
    }

    public String getUserDomain() {
        return userDomain;
    }

    public String getGender() {
        return gender;
    }

    public int getFollowersCount() {
        return followersCount;
    }

    public int getFriendsCount() {
        return friendsCount;
    }

    public int getStatusesCount() {
        return statusesCount;
    }

    public int getFavouritesCount() {
        return favouritesCount;
    }

    public Date getCreatedAt() {
        return createdAt;
    }

    public boolean isFollowing() {
        return following;
    }

    public boolean isVerified() {
        return verified;
    }

    public int getverifiedType() {
        return verifiedType;
    }

    public boolean isallowAllActMsg() {
        return allowAllActMsg;
    }

    public boolean isallowAllComment() {
        return allowAllComment;
    }

    public boolean isfollowMe() {
        return followMe;
    }

    public String getavatarLarge() {
        return avatarLarge;
    }

    public int getonlineStatus() {
        return onlineStatus;
    }

    public Status getStatus() {
        return status;
    }

    public int getbiFollowersCount() {
        return biFollowersCount;
    }

    public String getRemark() {
        return remark;
    }

    public String getLang() {
        return lang;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((id == null) ? 0 : id.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        User other = (User) obj;
        if (id == null) {
            if (other.id != null)
                return false;
        } else if (!id.equals(other.id))
            return false;
        return true;
    }

    @Override
    public String toString() {
        return "User [" + "id=" + id + ", screenName=" + screenName + ", name="
                + name + ", province=" + province + ", city=" + city
                + ", location=" + location + ", description=" + description
                + ", url=" + url + ", profileImageUrl=" + profileImageUrl
                + ", userDomain=" + userDomain + ", gender=" + gender
                + ", followersCount=" + followersCount + ", friendsCount="
                + friendsCount + ", statusesCount=" + statusesCount
                + ", favouritesCount=" + favouritesCount + ", createdAt="
                + createdAt + ", following=" + following + ", verified="
                + verified + ", verifiedType=" + verifiedType
                + ", allowAllActMsg=" + allowAllActMsg + ", allowAllComment="
                + allowAllComment + ", followMe=" + followMe + ", avatarLarge="
                + avatarLarge + ", onlineStatus=" + onlineStatus + ", status="
                + status + ", biFollowersCount=" + biFollowersCount
                + ", remark=" + remark + ", lang=" + lang + ", verifiedReason="
                + verifiedReason + ", weihao=" + weihao + ", statusId="
                + statusId + "]";
    }

}

UserTrend.java

package weibo4j.model;

import java.util.ArrayList;
import java.util.List;

import weibo4j.http.Response;
import weibo4j.org.json.JSONArray;
import weibo4j.org.json.JSONException;
import weibo4j.org.json.JSONObject;

/**
 * 话题
 * 
 * @author SinaWeibo
 * @since weibo4j-V2 1.0.0
 */
public class UserTrend extends WeiboResponse {
    private String num;
    private String hotword = null;
    private String trendId = null;
    private static final long serialVersionUID = 1925956704460743946L;

    public UserTrend() {
        super();
    }

    public UserTrend(Response res) throws WeiboException {
        super(res);
        JSONObject json = res.asJSONObject();
        try {
            num = json.getString("num");
            hotword = json.getString("hotword");
            trendId = json.getString("trend_id");
            if (json.getString("topicid") != null)
                trendId = json.getString("topicid");
        } catch (JSONException je) {
            throw new WeiboException(je.getMessage() + ":" + json.toString(),
                    je);
        }
    }

    public UserTrend(JSONObject json) throws WeiboException {
        try {
            num = json.getString("num");
            hotword = json.getString("hotword");
            trendId = json.getString("trend_id");
        } catch (JSONException je) {
            throw new WeiboException(je.getMessage() + ":" + json.toString(),
                    je);
        }
    }

    public static List<UserTrend> constructTrendList(Response res)
            throws WeiboException {
        try {
            JSONArray list = res.asJSONArray();
            int size = list.length();
            List<UserTrend> trends = new ArrayList<UserTrend>(size);
            for (int i = 0; i < size; i++) {
                trends.add(new UserTrend(list.getJSONObject(i)));
            }
            return trends;
        } catch (JSONException jsone) {
            throw new WeiboException(jsone);
        } catch (WeiboException te) {
            throw te;
        }

    }

    public String getNum() {
        return num;
    }

    public void setNum(String num) {
        this.num = num;
    }

    public String getHotword() {
        return hotword;
    }

    public void setHotword(String hotword) {
        this.hotword = hotword;
    }

    public String gettrendId() {
        return trendId;
    }

    public void settrendId(String trendId) {
        this.trendId = trendId;
    }

    @Override
    public String toString() {
        return "Trend [num=" + num + ", hotword=" + hotword + ", trendId="
                + trendId + "]";
    }

}

UserWapper.java

这里写代码片
package weibo4j.model;

import java.io.Serializable;
import java.util.List;

/**
 * 对User对象列表进行的包装,以支持cursor相关信息传递
 * 
 * @author sinaWeibo
 */
public class UserWapper implements Serializable {

    private static final long serialVersionUID = -3119107701303920284L;

    /**
     * 用户对象列表
     */
    private List<User> users;

    /**
     * 向前翻页的cursor
     */
    private long previousCursor;

    /**
     * 向后翻页的cursor
     */
    private long nextCursor;

    private long totalNumber;

    private String hasvisible;

    public UserWapper(List<User> users, long previousCursor, long nextCursor,
            long totalNumber, String hasvisible) {
        this.users = users;
        this.previousCursor = previousCursor;
        this.nextCursor = nextCursor;
        this.totalNumber = totalNumber;
        this.hasvisible = hasvisible;
    }

    public List<User> getUsers() {
        return users;
    }

    public void setUsers(List<User> users) {
        this.users = users;
    }

    public long getPreviousCursor() {
        return previousCursor;
    }

    public void setPreviousCursor(long previousCursor) {
        this.previousCursor = previousCursor;
    }

    public long getNextCursor() {
        return nextCursor;
    }

    public void setNextCursor(long nextCursor) {
        this.nextCursor = nextCursor;
    }

    public long getTotalNumber() {
        return totalNumber;
    }

    public void setTotalNumber(long totalNumber) {
        this.totalNumber = totalNumber;
    }

    public String getHasvisible() {
        return hasvisible;
    }

    public void setHasvisible(String hasvisible) {
        this.hasvisible = hasvisible;
    }

}

Version.java


package weibo4j.model;


public class Version {
    private final static String VERSION = "1.0.0";
    private final static String TITLE = "weibo4jV2";

    public static String getVersion() {
        return VERSION;
    }

    public static void main(String[] args) {
        System.out.println(TITLE + " " + VERSION);
    }
}

Visible.java

package weibo4j.model;

import weibo4j.org.json.JSONException;
import weibo4j.org.json.JSONObject;

public class Visible {
    private int type;
    private int list_id;

    public Visible(JSONObject json) throws JSONException {
        this.type = json.getInt("type");
        this.list_id = json.getInt("list_id");
    }

    public int getType() {
        return type;
    }

    public void setType(int type) {
        this.type = type;
    }

    public int getList_id() {
        return list_id;
    }

    public void setList_id(int list_id) {
        this.list_id = list_id;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + list_id;
        result = prime * result + type;
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Visible other = (Visible) obj;
        if (list_id != other.list_id)
            return false;
        if (type != other.type)
            return false;
        return true;
    }

    @Override
    public String toString() {
        return "Visible [type=" + type + ", list_id=" + list_id + "]";
    }

}

WeiboException.java


package weibo4j.model;

import weibo4j.org.json.JSONException;
import weibo4j.org.json.JSONObject;


public class WeiboException extends Exception {
    private int statusCode = -1;
    private int errorCode = -1;
    private String request;
    private String error;
    private static final long serialVersionUID = -2623309261327598087L;

    public WeiboException(String msg) {
        super(msg);
    }

    public WeiboException(Exception cause) {
        super(cause);
    }

    public WeiboException(String msg, int statusCode) throws JSONException {
        super(msg);
        this.statusCode = statusCode;
    }

    public WeiboException(String msg, JSONObject json, int statusCode)
            throws JSONException {
        super(msg + "\n error:" + json.getString("error") + " error_code:"
                + json.getInt("error_code") + json.getString("request"));
        this.statusCode = statusCode;
        this.errorCode = json.getInt("error_code");
        this.error = json.getString("error");
        this.request = json.getString("request");

    }

    public WeiboException(String msg, Exception cause) {
        super(msg, cause);
    }

    public WeiboException(String msg, Exception cause, int statusCode) {
        super(msg, cause);
        this.statusCode = statusCode;

    }

    public int getStatusCode() {
        return this.statusCode;
    }

    public int getErrorCode() {
        return errorCode;
    }

    public String getRequest() {
        return request;
    }

    public String getError() {
        return error;
    }

}

WeiboResponse.java


package weibo4j.model;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import weibo4j.http.HTMLEntity;
import weibo4j.http.Response;
import weibo4j.org.json.JSONException;
import weibo4j.org.json.JSONObject;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;


public class WeiboResponse implements java.io.Serializable {
    private static Map<String, SimpleDateFormat> formatMap = new HashMap<String, SimpleDateFormat>();
    private static final long serialVersionUID = 3519962197957449562L;
    private transient int rateLimitLimit = -1;
    private transient int rateLimitRemaining = -1;
    private transient long rateLimitReset = -1;
    private static final boolean IS_DALVIK = Configuration.isDalvik();

    public WeiboResponse() {
    }

    public WeiboResponse(Response res) {
        String limit = res.getResponseHeader("X-RateLimit-Limit");
        if (null != limit) {
            rateLimitLimit = Integer.parseInt(limit);
        }
        String remaining = res.getResponseHeader("X-RateLimit-Remaining");
        if (null != remaining) {
            rateLimitRemaining = Integer.parseInt(remaining);
        }
        String reset = res.getResponseHeader("X-RateLimit-Reset");
        if (null != reset) {
            rateLimitReset = Long.parseLong(reset);
        }
    }

    protected static void ensureRootNodeNameIs(String rootName, Element elem)
            throws WeiboException {
        if (!rootName.equals(elem.getNodeName())) {
            throw new WeiboException(
                    "Unexpected root node name:"
                            + elem.getNodeName()
                            + ". Expected:"
                            + rootName
                            + ". Check the availability of the Weibo API at http://open.t.sina.com.cn/.");
        }
    }

    protected static void ensureRootNodeNameIs(String[] rootNames, Element elem)
            throws WeiboException {
        String actualRootName = elem.getNodeName();
        for (String rootName : rootNames) {
            if (rootName.equals(actualRootName)) {
                return;
            }
        }
        String expected = "";
        for (int i = 0; i < rootNames.length; i++) {
            if (i != 0) {
                expected += " or ";
            }
            expected += rootNames[i];
        }
        throw new WeiboException(
                "Unexpected root node name:"
                        + elem.getNodeName()
                        + ". Expected:"
                        + expected
                        + ". Check the availability of the Weibo API at http://open.t.sina.com.cn/.");
    }

    protected static void ensureRootNodeNameIs(String rootName, Document doc)
            throws WeiboException {
        Element elem = doc.getDocumentElement();
        if (!rootName.equals(elem.getNodeName())) {
            throw new WeiboException(
                    "Unexpected root node name:"
                            + elem.getNodeName()
                            + ". Expected:"
                            + rootName
                            + ". Check the availability of the Weibo API at http://open.t.sina.com.cn/");
        }
    }

    protected static boolean isRootNodeNilClasses(Document doc) {
        String root = doc.getDocumentElement().getNodeName();
        return "nil-classes".equals(root) || "nilclasses".equals(root);
    }

    protected static String getChildText(String str, Element elem) {
        return HTMLEntity.unescape(getTextContent(str, elem));
    }

    protected static String getTextContent(String str, Element elem) {
        NodeList nodelist = elem.getElementsByTagName(str);
        if (nodelist.getLength() > 0) {
            Node node = nodelist.item(0).getFirstChild();
            if (null != node) {
                String nodeValue = node.getNodeValue();
                return null != nodeValue ? nodeValue : "";
            }
        }
        return "";
    }

    /* modify by sycheng add "".equals(str) */
    protected static int getChildInt(String str, Element elem) {
        String str2 = getTextContent(str, elem);
        if (null == str2 || "".equals(str2) || "null".equals(str)) {
            return -1;
        } else {
            return Integer.valueOf(str2);
        }
    }

    protected static long getChildLong(String str, Element elem) {
        String str2 = getTextContent(str, elem);
        if (null == str2 || "".equals(str2) || "null".equals(str)) {
            return -1;
        } else {
            return Long.valueOf(str2);
        }
    }

    protected static String getString(String name, JSONObject json,
            boolean decode) {
        String returnValue = null;
        try {
            returnValue = json.getString(name);
            if (decode) {
                try {
                    returnValue = URLDecoder.decode(returnValue, "UTF-8");
                } catch (UnsupportedEncodingException ignore) {
                }
            }
        } catch (JSONException ignore) {
            // refresh_url could be missing
        }
        return returnValue;
    }

    protected static boolean getChildBoolean(String str, Element elem) {
        String value = getTextContent(str, elem);
        return Boolean.valueOf(value);
    }

    protected static Date getChildDate(String str, Element elem)
            throws WeiboException {
        return getChildDate(str, elem, "EEE MMM d HH:mm:ss z yyyy");
    }

    protected static Date getChildDate(String str, Element elem, String format)
            throws WeiboException {
        return parseDate(getChildText(str, elem), format);
    }

    protected static Date parseDate(String str, String format)
            throws WeiboException {
        if (str == null || "".equals(str)) {
            return null;
        }
        SimpleDateFormat sdf = formatMap.get(format);
        if (null == sdf) {
            sdf = new SimpleDateFormat(format, Locale.ENGLISH);
            sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
            formatMap.put(format, sdf);
        }
        try {
            synchronized (sdf) {
                // SimpleDateFormat is not thread safe
                return sdf.parse(str);
            }
        } catch (ParseException pe) {
            throw new WeiboException("Unexpected format(" + str
                    + ") returned from sina.com.cn");
        }
    }

    protected static int getInt(String key, JSONObject json)
            throws JSONException {
        String str = json.getString(key);
        if (null == str || "".equals(str) || "null".equals(str)) {
            return -1;
        }
        return Integer.parseInt(str);
    }

    protected static long getLong(String key, JSONObject json)
            throws JSONException {
        String str = json.getString(key);
        if (null == str || "".equals(str) || "null".equals(str)) {
            return -1;
        }
        return Long.parseLong(str);
    }

    protected static boolean getBoolean(String key, JSONObject json)
            throws JSONException {
        String str = json.getString(key);
        if (null == str || "".equals(str) || "null".equals(str)) {
            return false;
        }
        return Boolean.valueOf(str);
    }

    public int getRateLimitLimit() {
        return rateLimitLimit;
    }

    public int getRateLimitRemaining() {
        return rateLimitRemaining;
    }

    public long getRateLimitReset() {
        return rateLimitReset;
    }
}

weibo4j.org.json包

CDL.java

package weibo4j.org.json;


public class CDL {

    /**
     * Get the next value. The value can be wrapped in quotes. The value can be
     * empty.
     * 
     * @param x
     *            A JSONTokener of the source text.
     * @return The value string, or null if empty.
     * @throws JSONException
     *             if the quoted string is badly formed.
     */
    private static String getValue(JSONTokener x) throws JSONException {
        char c;
        do {
            c = x.next();
        } while (c == ' ' || c == '\t');
        switch (c) {
        case 0:
            return null;
        case '"':
        case '\'':
            return x.nextString(c);
        case ',':
            x.back();
            return "";
        default:
            x.back();
            return x.nextTo(',');
        }
    }

    /**
     * Produce a JSONArray of strings from a row of comma delimited values.
     * 
     * @param x
     *            A JSONTokener of the source text.
     * @return A JSONArray of strings.
     * @throws JSONException
     */
    public static JSONArray rowToJSONArray(JSONTokener x) throws JSONException {
        JSONArray ja = new JSONArray();
        for (;;) {
            String value = getValue(x);
            if (value == null || (ja.length() == 0 && value.length() == 0)) {
                return null;
            }
            ja.put(value);
            for (;;) {
                char c = x.next();
                if (c == ',') {
                    break;
                }
                if (c != ' ') {
                    if (c == '\n' || c == '\r' || c == 0) {
                        return ja;
                    }
                    throw x.syntaxError("Bad character '" + c + "' (" + (int) c
                            + ").");
                }
            }
        }
    }

    /**
     * Produce a JSONObject from a row of comma delimited text, using a parallel
     * JSONArray of strings to provides the names of the elements.
     * 
     * @param names
     *            A JSONArray of names. This is commonly obtained from the first
     *            row of a comma delimited text file using the rowToJSONArray
     *            method.
     * @param x
     *            A JSONTokener of the source text.
     * @return A JSONObject combining the names and values.
     * @throws JSONException
     */
    public static JSONObject rowToJSONObject(JSONArray names, JSONTokener x)
            throws JSONException {
        JSONArray ja = rowToJSONArray(x);
        return ja != null ? ja.toJSONObject(names) : null;
    }

    /**
     * Produce a JSONArray of JSONObjects from a comma delimited text string,
     * using the first row as a source of names.
     * 
     * @param string
     *            The comma delimited text.
     * @return A JSONArray of JSONObjects.
     * @throws JSONException
     */
    public static JSONArray toJSONArray(String string) throws JSONException {
        return toJSONArray(new JSONTokener(string));
    }

    /**
     * Produce a JSONArray of JSONObjects from a comma delimited text string,
     * using the first row as a source of names.
     * 
     * @param x
     *            The JSONTokener containing the comma delimited text.
     * @return A JSONArray of JSONObjects.
     * @throws JSONException
     */
    public static JSONArray toJSONArray(JSONTokener x) throws JSONException {
        return toJSONArray(rowToJSONArray(x), x);
    }

    /**
     * Produce a JSONArray of JSONObjects from a comma delimited text string
     * using a supplied JSONArray as the source of element names.
     * 
     * @param names
     *            A JSONArray of strings.
     * @param string
     *            The comma delimited text.
     * @return A JSONArray of JSONObjects.
     * @throws JSONException
     */
    public static JSONArray toJSONArray(JSONArray names, String string)
            throws JSONException {
        return toJSONArray(names, new JSONTokener(string));
    }

    /**
     * Produce a JSONArray of JSONObjects from a comma delimited text string
     * using a supplied JSONArray as the source of element names.
     * 
     * @param names
     *            A JSONArray of strings.
     * @param x
     *            A JSONTokener of the source text.
     * @return A JSONArray of JSONObjects.
     * @throws JSONException
     */
    public static JSONArray toJSONArray(JSONArray names, JSONTokener x)
            throws JSONException {
        if (names == null || names.length() == 0) {
            return null;
        }
        JSONArray ja = new JSONArray();
        for (;;) {
            JSONObject jo = rowToJSONObject(names, x);
            if (jo == null) {
                break;
            }
            ja.put(jo);
        }
        if (ja.length() == 0) {
            return null;
        }
        return ja;
    }

    /**
     * Produce a comma delimited text row from a JSONArray. Values containing
     * the comma character will be quoted.
     * 
     * @param ja
     *            A JSONArray of strings.
     * @return A string ending in NEWLINE.
     */
    public static String rowToString(JSONArray ja) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < ja.length(); i += 1) {
            if (i > 0) {
                sb.append(',');
            }
            Object o = ja.opt(i);
            if (o != null) {
                String s = o.toString();
                if (s.indexOf(',') >= 0) {
                    if (s.indexOf('"') >= 0) {
                        sb.append('\'');
                        sb.append(s);
                        sb.append('\'');
                    } else {
                        sb.append('"');
                        sb.append(s);
                        sb.append('"');
                    }
                } else {
                    sb.append(s);
                }
            }
        }
        sb.append('\n');
        return sb.toString();

    }

    /**
     * Produce a comma delimited text from a JSONArray of JSONObjects. The first
     * row will be a list of names obtained by inspecting the first JSONObject.
     * 
     * @param ja
     *            A JSONArray of JSONObjects.
     * @return A comma delimited text.
     * @throws JSONException
     */
    public static String toString(JSONArray ja) throws JSONException {
        JSONObject jo = ja.optJSONObject(0);
        if (jo != null) {
            JSONArray names = jo.names();
            if (names != null) {
                return rowToString(names) + toString(names, ja);
            }
        }
        return null;
    }

    /**
     * Produce a comma delimited text from a JSONArray of JSONObjects using a
     * provided list of names. The list of names is not included in the output.
     * 
     * @param names
     *            A JSONArray of strings.
     * @param ja
     *            A JSONArray of JSONObjects.
     * @return A comma delimited text.
     * @throws JSONException
     */
    public static String toString(JSONArray names, JSONArray ja)
            throws JSONException {
        if (names == null || names.length() == 0) {
            return null;
        }
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < ja.length(); i += 1) {
            JSONObject jo = ja.optJSONObject(i);
            if (jo != null) {
                sb.append(rowToString(jo.toJSONArray(names)));
            }
        }
        return sb.toString();
    }
}

Cookie.java

package weibo4j.org.json;


public class Cookie {


    public static String escape(String string) {
        char c;
        String s = string.trim();
        StringBuffer sb = new StringBuffer();
        int len = s.length();
        for (int i = 0; i < len; i += 1) {
            c = s.charAt(i);
            if (c < ' ' || c == '+' || c == '%' || c == '=' || c == ';') {
                sb.append('%');
                sb.append(Character.forDigit((char) ((c >>> 4) & 0x0f), 16));
                sb.append(Character.forDigit((char) (c & 0x0f), 16));
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    /**
     * Convert a cookie specification string into a JSONObject. The string will
     * contain a name value pair separated by '='. The name and the value will
     * be unescaped, possibly converting '+' and '%' sequences. The cookie
     * properties may follow, separated by ';', also represented as name=value
     * (except the secure property, which does not have a value). The name will
     * be stored under the key "name", and the value will be stored under the
     * key "value". This method does not do checking or validation of the
     * parameters. It only converts the cookie string into a JSONObject.
     * 
     * @param string
     *            The cookie specification string.
     * @return A JSONObject containing "name", "value", and possibly other
     *         members.
     * @throws JSONException
     */
    public static JSONObject toJSONObject(String string) throws JSONException {
        String n;
        JSONObject o = new JSONObject();
        Object v;
        JSONTokener x = new JSONTokener(string);
        o.put("name", x.nextTo('='));
        x.next('=');
        o.put("value", x.nextTo(';'));
        x.next();
        while (x.more()) {
            n = unescape(x.nextTo("=;"));
            if (x.next() != '=') {
                if (n.equals("secure")) {
                    v = Boolean.TRUE;
                } else {
                    throw x.syntaxError("Missing '=' in cookie parameter.");
                }
            } else {
                v = unescape(x.nextTo(';'));
                x.next();
            }
            o.put(n, v);
        }
        return o;
    }

    /**
     * Convert a JSONObject into a cookie specification string. The JSONObject
     * must contain "name" and "value" members. If the JSONObject contains
     * "expires", "domain", "path", or "secure" members, they will be appended
     * to the cookie specification string. All other members are ignored.
     * 
     * @param o
     *            A JSONObject
     * @return A cookie specification string
     * @throws JSONException
     */
    public static String toString(JSONObject o) throws JSONException {
        StringBuffer sb = new StringBuffer();

        sb.append(escape(o.getString("name")));
        sb.append("=");
        sb.append(escape(o.getString("value")));
        if (o.has("expires")) {
            sb.append(";expires=");
            sb.append(o.getString("expires"));
        }
        if (o.has("domain")) {
            sb.append(";domain=");
            sb.append(escape(o.getString("domain")));
        }
        if (o.has("path")) {
            sb.append(";path=");
            sb.append(escape(o.getString("path")));
        }
        if (o.optBoolean("secure")) {
            sb.append(";secure");
        }
        return sb.toString();
    }

    /**
     * Convert <code>%</code><i>hh</i> sequences to single characters, and
     * convert plus to space.
     * 
     * @param s
     *            A string that may contain <code>+</code>
     *            &nbsp;<small>(plus)</small> and <code>%</code><i>hh</i>
     *            sequences.
     * @return The unescaped string.
     */
    public static String unescape(String s) {
        int len = s.length();
        StringBuffer b = new StringBuffer();
        for (int i = 0; i < len; ++i) {
            char c = s.charAt(i);
            if (c == '+') {
                c = ' ';
            } else if (c == '%' && i + 2 < len) {
                int d = JSONTokener.dehexchar(s.charAt(i + 1));
                int e = JSONTokener.dehexchar(s.charAt(i + 2));
                if (d >= 0 && e >= 0) {
                    c = (char) (d * 16 + e);
                    i += 2;
                }
            }
            b.append(c);
        }
        return b.toString();
    }
}

CookieList.java

package weibo4j.org.json;


import java.util.Iterator;


public class CookieList {


    public static JSONObject toJSONObject(String string) throws JSONException {
        JSONObject o = new JSONObject();
        JSONTokener x = new JSONTokener(string);
        while (x.more()) {
            String name = Cookie.unescape(x.nextTo('='));
            x.next('=');
            o.put(name, Cookie.unescape(x.nextTo(';')));
            x.next();
        }
        return o;
    }

    /**
     * Convert a JSONObject into a cookie list. A cookie list is a sequence of
     * name/value pairs. The names are separated from the values by '='. The
     * pairs are separated by ';'. The characters '%', '+', '=', and ';' in the
     * names and values are replaced by "%hh".
     * 
     * @param o
     *            A JSONObject
     * @return A cookie list string
     * @throws JSONException
     */
    public static String toString(JSONObject o) throws JSONException {
        boolean b = false;
        Iterator keys = o.keys();
        String s;
        StringBuffer sb = new StringBuffer();
        while (keys.hasNext()) {
            s = keys.next().toString();
            if (!o.isNull(s)) {
                if (b) {
                    sb.append(';');
                }
                sb.append(Cookie.escape(s));
                sb.append("=");
                sb.append(Cookie.escape(o.getString(s)));
                b = true;
            }
        }
        return sb.toString();
    }
}

HTTP.java

package weibo4j.org.json;

import java.util.Iterator;

/**
 * Convert an HTTP header to a JSONObject and back.
 * 
 * @author JSON.org
 * @version 2008-09-18
 */
public class HTTP {

    /** Carriage return/line feed. */
    public static final String CRLF = "\r\n";

    /**
     * Convert an HTTP header string into a JSONObject. It can be a request
     * header or a response header. A request header will contain
     * 
     * <pre>
     * {
     *    Method: "POST" (for example),
     *    "Request-URI": "/" (for example),
     *    "HTTP-Version": "HTTP/1.1" (for example)
     * }
     * </pre>
     * 
     * A response header will contain
     * 
     * <pre>
     * {
     *    "HTTP-Version": "HTTP/1.1" (for example),
     *    "Status-Code": "200" (for example),
     *    "Reason-Phrase": "OK" (for example)
     * }
     * </pre>
     * 
     * In addition, the other parameters in the header will be captured, using
     * the HTTP field names as JSON names, so that
     * 
     * <pre>
     *    Date: Sun, 26 May 2002 18:06:04 GMT
     *    Cookie: Q=q2=PPEAsg--; B=677gi6ouf29bn&b=2&f=s
     *    Cache-Control: no-cache
     * </pre>
     * 
     * become
     * 
     * <pre>
     * {...
     *    Date: "Sun, 26 May 2002 18:06:04 GMT",
     *    Cookie: "Q=q2=PPEAsg--; B=677gi6ouf29bn&b=2&f=s",
     *    "Cache-Control": "no-cache",
     * ...}
     * </pre>
     * 
     * It does no further checking or conversion. It does not parse dates. It
     * does not do '%' transforms on URLs.
     * 
     * @param string
     *            An HTTP header string.
     * @return A JSONObject containing the elements and attributes of the XML
     *         string.
     * @throws JSONException
     */
    public static JSONObject toJSONObject(String string) throws JSONException {
        JSONObject o = new JSONObject();
        HTTPTokener x = new HTTPTokener(string);
        String t;

        t = x.nextToken();
        if (t.toUpperCase().startsWith("HTTP")) {

            // Response

            o.put("HTTP-Version", t);
            o.put("Status-Code", x.nextToken());
            o.put("Reason-Phrase", x.nextTo('\0'));
            x.next();

        } else {

            // Request

            o.put("Method", t);
            o.put("Request-URI", x.nextToken());
            o.put("HTTP-Version", x.nextToken());
        }

        // Fields

        while (x.more()) {
            String name = x.nextTo(':');
            x.next(':');
            o.put(name, x.nextTo('\0'));
            x.next();
        }
        return o;
    }

    /**
     * Convert a JSONObject into an HTTP header. A request header must contain
     * 
     * <pre>
     * {
     *    Method: "POST" (for example),
     *    "Request-URI": "/" (for example),
     *    "HTTP-Version": "HTTP/1.1" (for example)
     * }
     * </pre>
     * 
     * A response header must contain
     * 
     * <pre>
     * {
     *    "HTTP-Version": "HTTP/1.1" (for example),
     *    "Status-Code": "200" (for example),
     *    "Reason-Phrase": "OK" (for example)
     * }
     * </pre>
     * 
     * Any other members of the JSONObject will be output as HTTP fields. The
     * result will end with two CRLF pairs.
     * 
     * @param o
     *            A JSONObject
     * @return An HTTP header string.
     * @throws JSONException
     *             if the object does not contain enough information.
     */
    public static String toString(JSONObject o) throws JSONException {
        Iterator keys = o.keys();
        String s;
        StringBuffer sb = new StringBuffer();
        if (o.has("Status-Code") && o.has("Reason-Phrase")) {
            sb.append(o.getString("HTTP-Version"));
            sb.append(' ');
            sb.append(o.getString("Status-Code"));
            sb.append(' ');
            sb.append(o.getString("Reason-Phrase"));
        } else if (o.has("Method") && o.has("Request-URI")) {
            sb.append(o.getString("Method"));
            sb.append(' ');
            sb.append('"');
            sb.append(o.getString("Request-URI"));
            sb.append('"');
            sb.append(' ');
            sb.append(o.getString("HTTP-Version"));
        } else {
            throw new JSONException("Not enough material for an HTTP header.");
        }
        sb.append(CRLF);
        while (keys.hasNext()) {
            s = keys.next().toString();
            if (!s.equals("HTTP-Version") && !s.equals("Status-Code")
                    && !s.equals("Reason-Phrase") && !s.equals("Method")
                    && !s.equals("Request-URI") && !o.isNull(s)) {
                sb.append(s);
                sb.append(": ");
                sb.append(o.getString(s));
                sb.append(CRLF);
            }
        }
        sb.append(CRLF);
        return sb.toString();
    }
}

HTTPTokener.java

package weibo4j.org.json;


public class HTTPTokener extends JSONTokener {

    /**
     * Construct an XMLTokener from a string.
     * 
     * @param s
     *            A source string.
     */
    public HTTPTokener(String s) {
        super(s);
    }

    /**
     * Get the next token or string. This is used in parsing HTTP headers.
     * 
     * @throws JSONException
     * @return A String.
     */
    public String nextToken() throws JSONException {
        char c;
        char q;
        StringBuffer sb = new StringBuffer();
        do {
            c = next();
        } while (Character.isWhitespace(c));
        if (c == '"' || c == '\'') {
            q = c;
            for (;;) {
                c = next();
                if (c < ' ') {
                    throw syntaxError("Unterminated string.");
                }
                if (c == q) {
                    return sb.toString();
                }
                sb.append(c);
            }
        }
        for (;;) {
            if (c == 0 || Character.isWhitespace(c)) {
                return sb.toString();
            }
            sb.append(c);
            c = next();
        }
    }
}

JSONArray.java

package weibo4j.org.json;



import java.io.IOException;
import java.io.Writer;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;


public class JSONArray {

    /**
     * The arrayList where the JSONArray's properties are kept.
     */
    private ArrayList myArrayList;

    /**
     * Construct an empty JSONArray.
     */
    public JSONArray() {
        this.myArrayList = new ArrayList();
    }

    /**
     * Construct a JSONArray from a JSONTokener.
     * 
     * @param x
     *            A JSONTokener
     * @throws JSONException
     *             If there is a syntax error.
     */
    public JSONArray(JSONTokener x) throws JSONException {
        this();
        char c = x.nextClean();
        char q;
        if (c == '[') {
            q = ']';
        } else if (c == '(') {
            q = ')';
        } else {
            throw x.syntaxError("A JSONArray text must start with '['");
        }
        if (x.nextClean() == ']') {
            return;
        }
        x.back();
        for (;;) {
            if (x.nextClean() == ',') {
                x.back();
                this.myArrayList.add(null);
            } else {
                x.back();
                this.myArrayList.add(x.nextValue());
            }
            c = x.nextClean();
            switch (c) {
            case ';':
            case ',':
                if (x.nextClean() == ']') {
                    return;
                }
                x.back();
                break;
            case ']':
            case ')':
                if (q != c) {
                    throw x.syntaxError("Expected a '" + new Character(q) + "'");
                }
                return;
            default:
                throw x.syntaxError("Expected a ',' or ']'");
            }
        }
    }

    /**
     * Construct a JSONArray from a source JSON text.
     * 
     * @param source
     *            A string that begins with <code>[</code>&nbsp;<small>(left
     *            bracket)</small> and ends with <code>]</code>
     *            &nbsp;<small>(right bracket)</small>.
     * @throws JSONException
     *             If there is a syntax error.
     */
    public JSONArray(String source) throws JSONException {
        this(new JSONTokener(source));
    }

    /**
     * Construct a JSONArray from a Collection.
     * 
     * @param collection
     *            A Collection.
     */
    public JSONArray(Collection collection) {
        this.myArrayList = (collection == null) ? new ArrayList()
                : new ArrayList(collection);
    }

    /**
     * Construct a JSONArray from a collection of beans. The collection should
     * have Java Beans.
     * 
     * @throws JSONException
     *             If not an array.
     */

    public JSONArray(Collection collection, boolean includeSuperClass) {
        this.myArrayList = new ArrayList();
        if (collection != null) {
            for (Iterator iter = collection.iterator(); iter.hasNext();) {
                this.myArrayList.add(new JSONObject(iter.next(),
                        includeSuperClass));
            }
        }
    }

    /**
     * Construct a JSONArray from an array
     * 
     * @throws JSONException
     *             If not an array.
     */
    public JSONArray(Object array) throws JSONException {
        this();
        if (array.getClass().isArray()) {
            int length = Array.getLength(array);
            for (int i = 0; i < length; i += 1) {
                this.put(Array.get(array, i));
            }
        } else {
            throw new JSONException(
                    "JSONArray initial value should be a string or collection or array.");
        }
    }

    /**
     * Construct a JSONArray from an array with a bean. The array should have
     * Java Beans.
     * 
     * @throws JSONException
     *             If not an array.
     */
    public JSONArray(Object array, boolean includeSuperClass)
            throws JSONException {
        this();
        if (array.getClass().isArray()) {
            int length = Array.getLength(array);
            for (int i = 0; i < length; i += 1) {
                this.put(new JSONObject(Array.get(array, i), includeSuperClass));
            }
        } else {
            throw new JSONException(
                    "JSONArray initial value should be a string or collection or array.");
        }
    }

    /**
     * Get the object value associated with an index.
     * 
     * @param index
     *            The index must be between 0 and length() - 1.
     * @return An object value.
     * @throws JSONException
     *             If there is no value for the index.
     */
    public Object get(int index) throws JSONException {
        Object o = opt(index);
        if (o == null) {
            throw new JSONException("JSONArray[" + index + "] not found.");
        }
        return o;
    }

    /**
     * Get the boolean value associated with an index. The string values "true"
     * and "false" are converted to boolean.
     * 
     * @param index
     *            The index must be between 0 and length() - 1.
     * @return The truth.
     * @throws JSONException
     *             If there is no value for the index or if the value is not
     *             convertable to boolean.
     */
    public boolean getBoolean(int index) throws JSONException {
        Object o = get(index);
        if (o.equals(Boolean.FALSE)
                || (o instanceof String && ((String) o)
                        .equalsIgnoreCase("false"))) {
            return false;
        } else if (o.equals(Boolean.TRUE)
                || (o instanceof String && ((String) o)
                        .equalsIgnoreCase("true"))) {
            return true;
        }
        throw new JSONException("JSONArray[" + index + "] is not a Boolean.");
    }

    /**
     * Get the double value associated with an index.
     * 
     * @param index
     *            The index must be between 0 and length() - 1.
     * @return The value.
     * @throws JSONException
     *             If the key is not found or if the value cannot be converted
     *             to a number.
     */
    public double getDouble(int index) throws JSONException {
        Object o = get(index);
        try {
            return o instanceof Number ? ((Number) o).doubleValue() : Double
                    .valueOf((String) o).doubleValue();
        } catch (Exception e) {
            throw new JSONException("JSONArray[" + index + "] is not a number.");
        }
    }

    /**
     * Get the int value associated with an index.
     * 
     * @param index
     *            The index must be between 0 and length() - 1.
     * @return The value.
     * @throws JSONException
     *             If the key is not found or if the value cannot be converted
     *             to a number. if the value cannot be converted to a number.
     */
    public int getInt(int index) throws JSONException {
        Object o = get(index);
        return o instanceof Number ? ((Number) o).intValue()
                : (int) getDouble(index);
    }

    /**
     * Get the JSONArray associated with an index.
     * 
     * @param index
     *            The index must be between 0 and length() - 1.
     * @return A JSONArray value.
     * @throws JSONException
     *             If there is no value for the index. or if the value is not a
     *             JSONArray
     */
    public JSONArray getJSONArray(int index) throws JSONException {
        Object o = get(index);
        if (o instanceof JSONArray) {
            return (JSONArray) o;
        }
        throw new JSONException("JSONArray[" + index + "] is not a JSONArray.");
    }

    /**
     * Get the JSONObject associated with an index.
     * 
     * @param index
     *            subscript
     * @return A JSONObject value.
     * @throws JSONException
     *             If there is no value for the index or if the value is not a
     *             JSONObject
     */
    public JSONObject getJSONObject(int index) throws JSONException {
        Object o = get(index);
        if (o instanceof JSONObject) {
            return (JSONObject) o;
        }
        throw new JSONException("JSONArray[" + index + "] is not a JSONObject.");
    }

    /**
     * Get the long value associated with an index.
     * 
     * @param index
     *            The index must be between 0 and length() - 1.
     * @return The value.
     * @throws JSONException
     *             If the key is not found or if the value cannot be converted
     *             to a number.
     */
    public long getLong(int index) throws JSONException {
        Object o = get(index);
        return o instanceof Number ? ((Number) o).longValue()
                : (long) getDouble(index);
    }

    /**
     * Get the string associated with an index.
     * 
     * @param index
     *            The index must be between 0 and length() - 1.
     * @return A string value.
     * @throws JSONException
     *             If there is no value for the index.
     */
    public String getString(int index) throws JSONException {
        return get(index).toString();
    }

    /**
     * Determine if the value is null.
     * 
     * @param index
     *            The index must be between 0 and length() - 1.
     * @return true if the value at the index is null, or if there is no value.
     */
    public boolean isNull(int index) {
        return JSONObject.NULL.equals(opt(index));
    }

    /**
     * Make a string from the contents of this JSONArray. The
     * <code>separator</code> string is inserted between each element. Warning:
     * This method assumes that the data structure is acyclical.
     * 
     * @param separator
     *            A string that will be inserted between the elements.
     * @return a string.
     * @throws JSONException
     *             If the array contains an invalid number.
     */
    public String join(String separator) throws JSONException {
        int len = length();
        StringBuffer sb = new StringBuffer();

        for (int i = 0; i < len; i += 1) {
            if (i > 0) {
                sb.append(separator);
            }
            sb.append(JSONObject.valueToString(this.myArrayList.get(i)));
        }
        return sb.toString();
    }

    /**
     * Get the number of elements in the JSONArray, included nulls.
     * 
     * @return The length (or size).
     */
    public int length() {
        return this.myArrayList.size();
    }

    /**
     * Get the optional object value associated with an index.
     * 
     * @param index
     *            The index must be between 0 and length() - 1.
     * @return An object value, or null if there is no object at that index.
     */
    public Object opt(int index) {
        return (index < 0 || index >= length()) ? null : this.myArrayList
                .get(index);
    }

    /**
     * Get the optional boolean value associated with an index. It returns false
     * if there is no value at that index, or if the value is not Boolean.TRUE
     * or the String "true".
     * 
     * @param index
     *            The index must be between 0 and length() - 1.
     * @return The truth.
     */
    public boolean optBoolean(int index) {
        return optBoolean(index, false);
    }

    /**
     * Get the optional boolean value associated with an index. It returns the
     * defaultValue if there is no value at that index or if it is not a Boolean
     * or the String "true" or "false" (case insensitive).
     * 
     * @param index
     *            The index must be between 0 and length() - 1.
     * @param defaultValue
     *            A boolean default.
     * @return The truth.
     */
    public boolean optBoolean(int index, boolean defaultValue) {
        try {
            return getBoolean(index);
        } catch (Exception e) {
            return defaultValue;
        }
    }

    /**
     * Get the optional double value associated with an index. NaN is returned
     * if there is no value for the index, or if the value is not a number and
     * cannot be converted to a number.
     * 
     * @param index
     *            The index must be between 0 and length() - 1.
     * @return The value.
     */
    public double optDouble(int index) {
        return optDouble(index, Double.NaN);
    }

    /**
     * Get the optional double value associated with an index. The defaultValue
     * is returned if there is no value for the index, or if the value is not a
     * number and cannot be converted to a number.
     * 
     * @param index
     *            subscript
     * @param defaultValue
     *            The default value.
     * @return The value.
     */
    public double optDouble(int index, double defaultValue) {
        try {
            return getDouble(index);
        } catch (Exception e) {
            return defaultValue;
        }
    }

    /**
     * Get the optional int value associated with an index. Zero is returned if
     * there is no value for the index, or if the value is not a number and
     * cannot be converted to a number.
     * 
     * @param index
     *            The index must be between 0 and length() - 1.
     * @return The value.
     */
    public int optInt(int index) {
        return optInt(index, 0);
    }

    /**
     * Get the optional int value associated with an index. The defaultValue is
     * returned if there is no value for the index, or if the value is not a
     * number and cannot be converted to a number.
     * 
     * @param index
     *            The index must be between 0 and length() - 1.
     * @param defaultValue
     *            The default value.
     * @return The value.
     */
    public int optInt(int index, int defaultValue) {
        try {
            return getInt(index);
        } catch (Exception e) {
            return defaultValue;
        }
    }

    /**
     * Get the optional JSONArray associated with an index.
     * 
     * @param index
     *            subscript
     * @return A JSONArray value, or null if the index has no value, or if the
     *         value is not a JSONArray.
     */
    public JSONArray optJSONArray(int index) {
        Object o = opt(index);
        return o instanceof JSONArray ? (JSONArray) o : null;
    }

    /**
     * Get the optional JSONObject associated with an index. Null is returned if
     * the key is not found, or null if the index has no value, or if the value
     * is not a JSONObject.
     * 
     * @param index
     *            The index must be between 0 and length() - 1.
     * @return A JSONObject value.
     */
    public JSONObject optJSONObject(int index) {
        Object o = opt(index);
        return o instanceof JSONObject ? (JSONObject) o : null;
    }

    /**
     * Get the optional long value associated with an index. Zero is returned if
     * there is no value for the index, or if the value is not a number and
     * cannot be converted to a number.
     * 
     * @param index
     *            The index must be between 0 and length() - 1.
     * @return The value.
     */
    public long optLong(int index) {
        return optLong(index, 0);
    }

    /**
     * Get the optional long value associated with an index. The defaultValue is
     * returned if there is no value for the index, or if the value is not a
     * number and cannot be converted to a number.
     * 
     * @param index
     *            The index must be between 0 and length() - 1.
     * @param defaultValue
     *            The default value.
     * @return The value.
     */
    public long optLong(int index, long defaultValue) {
        try {
            return getLong(index);
        } catch (Exception e) {
            return defaultValue;
        }
    }

    /**
     * Get the optional string value associated with an index. It returns an
     * empty string if there is no value at that index. If the value is not a
     * string and is not null, then it is coverted to a string.
     * 
     * @param index
     *            The index must be between 0 and length() - 1.
     * @return A String value.
     */
    public String optString(int index) {
        return optString(index, "");
    }

    /**
     * Get the optional string associated with an index. The defaultValue is
     * returned if the key is not found.
     * 
     * @param index
     *            The index must be between 0 and length() - 1.
     * @param defaultValue
     *            The default value.
     * @return A String value.
     */
    public String optString(int index, String defaultValue) {
        Object o = opt(index);
        return o != null ? o.toString() : defaultValue;
    }

    /**
     * Append a boolean value. This increases the array's length by one.
     * 
     * @param value
     *            A boolean value.
     * @return this.
     */
    public JSONArray put(boolean value) {
        put(value ? Boolean.TRUE : Boolean.FALSE);
        return this;
    }

    /**
     * Put a value in the JSONArray, where the value will be a JSONArray which
     * is produced from a Collection.
     * 
     * @param value
     *            A Collection value.
     * @return this.
     */
    public JSONArray put(Collection value) {
        put(new JSONArray(value));
        return this;
    }

    /**
     * Append a double value. This increases the array's length by one.
     * 
     * @param value
     *            A double value.
     * @throws JSONException
     *             if the value is not finite.
     * @return this.
     */
    public JSONArray put(double value) throws JSONException {
        Double d = new Double(value);
        JSONObject.testValidity(d);
        put(d);
        return this;
    }

    /**
     * Append an int value. This increases the array's length by one.
     * 
     * @param value
     *            An int value.
     * @return this.
     */
    public JSONArray put(int value) {
        put(new Integer(value));
        return this;
    }

    /**
     * Append an long value. This increases the array's length by one.
     * 
     * @param value
     *            A long value.
     * @return this.
     */
    public JSONArray put(long value) {
        put(new Long(value));
        return this;
    }

    /**
     * Put a value in the JSONArray, where the value will be a JSONObject which
     * is produced from a Map.
     * 
     * @param value
     *            A Map value.
     * @return this.
     */
    public JSONArray put(Map value) {
        put(new JSONObject(value));
        return this;
    }

    /**
     * Append an object value. This increases the array's length by one.
     * 
     * @param value
     *            An object value. The value should be a Boolean, Double,
     *            Integer, JSONArray, JSONObject, Long, or String, or the
     *            JSONObject.NULL object.
     * @return this.
     */
    public JSONArray put(Object value) {
        this.myArrayList.add(value);
        return this;
    }

    /**
     * Put or replace a boolean value in the JSONArray. If the index is greater
     * than the length of the JSONArray, then null elements will be added as
     * necessary to pad it out.
     * 
     * @param index
     *            The subscript.
     * @param value
     *            A boolean value.
     * @return this.
     * @throws JSONException
     *             If the index is negative.
     */
    public JSONArray put(int index, boolean value) throws JSONException {
        put(index, value ? Boolean.TRUE : Boolean.FALSE);
        return this;
    }

    /**
     * Put a value in the JSONArray, where the value will be a JSONArray which
     * is produced from a Collection.
     * 
     * @param index
     *            The subscript.
     * @param value
     *            A Collection value.
     * @return this.
     * @throws JSONException
     *             If the index is negative or if the value is not finite.
     */
    public JSONArray put(int index, Collection value) throws JSONException {
        put(index, new JSONArray(value));
        return this;
    }

    /**
     * Put or replace a double value. If the index is greater than the length of
     * the JSONArray, then null elements will be added as necessary to pad it
     * out.
     * 
     * @param index
     *            The subscript.
     * @param value
     *            A double value.
     * @return this.
     * @throws JSONException
     *             If the index is negative or if the value is not finite.
     */
    public JSONArray put(int index, double value) throws JSONException {
        put(index, new Double(value));
        return this;
    }

    /**
     * Put or replace an int value. If the index is greater than the length of
     * the JSONArray, then null elements will be added as necessary to pad it
     * out.
     * 
     * @param index
     *            The subscript.
     * @param value
     *            An int value.
     * @return this.
     * @throws JSONException
     *             If the index is negative.
     */
    public JSONArray put(int index, int value) throws JSONException {
        put(index, new Integer(value));
        return this;
    }

    /**
     * Put or replace a long value. If the index is greater than the length of
     * the JSONArray, then null elements will be added as necessary to pad it
     * out.
     * 
     * @param index
     *            The subscript.
     * @param value
     *            A long value.
     * @return this.
     * @throws JSONException
     *             If the index is negative.
     */
    public JSONArray put(int index, long value) throws JSONException {
        put(index, new Long(value));
        return this;
    }

    /**
     * Put a value in the JSONArray, where the value will be a JSONObject which
     * is produced from a Map.
     * 
     * @param index
     *            The subscript.
     * @param value
     *            The Map value.
     * @return this.
     * @throws JSONException
     *             If the index is negative or if the the value is an invalid
     *             number.
     */
    public JSONArray put(int index, Map value) throws JSONException {
        put(index, new JSONObject(value));
        return this;
    }

    /**
     * Put or replace an object value in the JSONArray. If the index is greater
     * than the length of the JSONArray, then null elements will be added as
     * necessary to pad it out.
     * 
     * @param index
     *            The subscript.
     * @param value
     *            The value to put into the array. The value should be a
     *            Boolean, Double, Integer, JSONArray, JSONObject, Long, or
     *            String, or the JSONObject.NULL object.
     * @return this.
     * @throws JSONException
     *             If the index is negative or if the the value is an invalid
     *             number.
     */
    public JSONArray put(int index, Object value) throws JSONException {
        JSONObject.testValidity(value);
        if (index < 0) {
            throw new JSONException("JSONArray[" + index + "] not found.");
        }
        if (index < length()) {
            this.myArrayList.set(index, value);
        } else {
            while (index != length()) {
                put(JSONObject.NULL);
            }
            put(value);
        }
        return this;
    }

    /**
     * Produce a JSONObject by combining a JSONArray of names with the values of
     * this JSONArray.
     * 
     * @param names
     *            A JSONArray containing a list of key strings. These will be
     *            paired with the values.
     * @return A JSONObject, or null if there are no names or if this JSONArray
     *         has no values.
     * @throws JSONException
     *             If any of the names are null.
     */
    public JSONObject toJSONObject(JSONArray names) throws JSONException {
        if (names == null || names.length() == 0 || length() == 0) {
            return null;
        }
        JSONObject jo = new JSONObject();
        for (int i = 0; i < names.length(); i += 1) {
            jo.put(names.getString(i), this.opt(i));
        }
        return jo;
    }

    /**
     * Make a JSON text of this JSONArray. For compactness, no unnecessary
     * whitespace is added. If it is not possible to produce a syntactically
     * correct JSON text then null will be returned instead. This could occur if
     * the array contains an invalid number.
     * <p>
     * Warning: This method assumes that the data structure is acyclical.
     * 
     * @return a printable, displayable, transmittable representation of the
     *         array.
     */
    public String toString() {
        try {
            return '[' + join(",") + ']';
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * Make a prettyprinted JSON text of this JSONArray. Warning: This method
     * assumes that the data structure is acyclical.
     * 
     * @param indentFactor
     *            The number of spaces to add to each level of indentation.
     * @return a printable, displayable, transmittable representation of the
     *         object, beginning with <code>[</code>&nbsp;<small>(left
     *         bracket)</small> and ending with <code>]</code>
     *         &nbsp;<small>(right bracket)</small>.
     * @throws JSONException
     */
    public String toString(int indentFactor) throws JSONException {
        return toString(indentFactor, 0);
    }

    /**
     * Make a prettyprinted JSON text of this JSONArray. Warning: This method
     * assumes that the data structure is acyclical.
     * 
     * @param indentFactor
     *            The number of spaces to add to each level of indentation.
     * @param indent
     *            The indention of the top level.
     * @return a printable, displayable, transmittable representation of the
     *         array.
     * @throws JSONException
     */
    String toString(int indentFactor, int indent) throws JSONException {
        int len = length();
        if (len == 0) {
            return "[]";
        }
        int i;
        StringBuffer sb = new StringBuffer("[");
        if (len == 1) {
            sb.append(JSONObject.valueToString(this.myArrayList.get(0),
                    indentFactor, indent));
        } else {
            int newindent = indent + indentFactor;
            sb.append('\n');
            for (i = 0; i < len; i += 1) {
                if (i > 0) {
                    sb.append(",\n");
                }
                for (int j = 0; j < newindent; j += 1) {
                    sb.append(' ');
                }
                sb.append(JSONObject.valueToString(this.myArrayList.get(i),
                        indentFactor, newindent));
            }
            sb.append('\n');
            for (i = 0; i < indent; i += 1) {
                sb.append(' ');
            }
        }
        sb.append(']');
        return sb.toString();
    }

    /**
     * Write the contents of the JSONArray as JSON text to a writer. For
     * compactness, no whitespace is added.
     * <p>
     * Warning: This method assumes that the data structure is acyclical.
     * 
     * @return The writer.
     * @throws JSONException
     */
    public Writer write(Writer writer) throws JSONException {
        try {
            boolean b = false;
            int len = length();

            writer.write('[');

            for (int i = 0; i < len; i += 1) {
                if (b) {
                    writer.write(',');
                }
                Object v = this.myArrayList.get(i);
                if (v instanceof JSONObject) {
                    ((JSONObject) v).write(writer);
                } else if (v instanceof JSONArray) {
                    ((JSONArray) v).write(writer);
                } else {
                    writer.write(JSONObject.valueToString(v));
                }
                b = true;
            }
            writer.write(']');
            return writer;
        } catch (IOException e) {
            throw new JSONException(e);
        }
    }
}

JSONException.java

package weibo4j.org.json;


public class JSONException extends Exception {
    private Throwable cause;

    /**
     * Constructs a JSONException with an explanatory message.
     * 
     * @param message
     *            Detail about the reason for the exception.
     */
    public JSONException(String message) {
        super(message);
    }

    public JSONException(Throwable t) {
        super(t.getMessage());
        this.cause = t;
    }

    public Throwable getCause() {
        return this.cause;
    }
}

JSONObject.java

package weibo4j.org.json;



import java.io.IOException;
import java.io.Writer;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeSet;


public class JSONObject {

    /**
     * JSONObject.NULL is equivalent to the value that JavaScript calls null,
     * whilst Java's null is equivalent to the value that JavaScript calls
     * undefined.
     */
    private static final class Null {

        /**
         * There is only intended to be a single instance of the NULL object, so
         * the clone method returns itself.
         * 
         * @return NULL.
         */
        protected final Object clone() {
            return this;
        }

        /**
         * A Null object is equal to the null value and to itself.
         * 
         * @param object
         *            An object to test for nullness.
         * @return true if the object parameter is the JSONObject.NULL object or
         *         null.
         */
        public boolean equals(Object object) {
            return object == null || object == this;
        }

        /**
         * Get the "null" string value.
         * 
         * @return The string "null".
         */
        public String toString() {
            return "null";
        }
    }

    /**
     * The map where the JSONObject's properties are kept.
     */
    private Map map;

    /**
     * It is sometimes more convenient and less ambiguous to have a
     * <code>NULL</code> object than to use Java's <code>null</code> value.
     * <code>JSONObject.NULL.equals(null)</code> returns <code>true</code>.
     * <code>JSONObject.NULL.toString()</code> returns <code>"null"</code>.
     */
    public static final Object NULL = new Null();

    /**
     * Construct an empty JSONObject.
     */
    public JSONObject() {
        this.map = new HashMap();
    }

    /**
     * Construct a JSONObject from a subset of another JSONObject. An array of
     * strings is used to identify the keys that should be copied. Missing keys
     * are ignored.
     * 
     * @param jo
     *            A JSONObject.
     * @param names
     *            An array of strings.
     * @exception JSONException
     *                If a value is a non-finite number or if a name is
     *                duplicated.
     */
    public JSONObject(JSONObject jo, String[] names) throws JSONException {
        this();
        for (int i = 0; i < names.length; i += 1) {
            putOnce(names[i], jo.opt(names[i]));
        }
    }

    /**
     * Construct a JSONObject from a JSONTokener.
     * 
     * @param x
     *            A JSONTokener object containing the source string.
     * @throws JSONException
     *             If there is a syntax error in the source string or a
     *             duplicated key.
     */
    public JSONObject(JSONTokener x) throws JSONException {
        this();
        char c;
        String key;

        if (x.nextClean() != '{') {
            throw x.syntaxError("A JSONObject text must begin with '{'");
        }
        for (;;) {
            c = x.nextClean();
            switch (c) {
            case 0:
                throw x.syntaxError("A JSONObject text must end with '}'");
            case '}':
                return;
            default:
                x.back();
                key = x.nextValue().toString();
            }

            /*
             * The key is followed by ':'. We will also tolerate '=' or '=>'.
             */

            c = x.nextClean();
            if (c == '=') {
                if (x.next() != '>') {
                    x.back();
                }
            } else if (c != ':') {
                throw x.syntaxError("Expected a ':' after a key");
            }
            putOnce(key, x.nextValue());

            /*
             * Pairs are separated by ','. We will also tolerate ';'.
             */

            switch (x.nextClean()) {
            case ';':
            case ',':
                if (x.nextClean() == '}') {
                    return;
                }
                x.back();
                break;
            case '}':
                return;
            default:
                throw x.syntaxError("Expected a ',' or '}'");
            }
        }
    }

    /**
     * Construct a JSONObject from a Map.
     * 
     * @param map
     *            A map object that can be used to initialize the contents of
     *            the JSONObject.
     */
    public JSONObject(Map map) {
        this.map = (map == null) ? new HashMap() : map;
    }

    /**
     * Construct a JSONObject from a Map.
     * 
     * Note: Use this constructor when the map contains <key,bean>.
     * 
     * @param map
     *            - A map with Key-Bean data.
     * @param includeSuperClass
     *            - Tell whether to include the super class properties.
     */
    public JSONObject(Map map, boolean includeSuperClass) {
        this.map = new HashMap();
        if (map != null) {
            for (Iterator i = map.entrySet().iterator(); i.hasNext();) {
                Map.Entry e = (Map.Entry) i.next();
                this.map.put(e.getKey(), new JSONObject(e.getValue(),
                        includeSuperClass));
            }
        }
    }

    /**
     * Construct a JSONObject from an Object using bean getters. It reflects on
     * all of the public methods of the object. For each of the methods with no
     * parameters and a name starting with <code>"get"</code> or
     * <code>"is"</code> followed by an uppercase letter, the method is invoked,
     * and a key and the value returned from the getter method are put into the
     * new JSONObject.
     * 
     * The key is formed by removing the <code>"get"</code> or <code>"is"</code>
     * prefix. If the second remaining character is not upper case, then the
     * first character is converted to lower case.
     * 
     * For example, if an object has a method named <code>"getName"</code>, and
     * if the result of calling <code>object.getName()</code> is
     * <code>"Larry Fine"</code>, then the JSONObject will contain
     * <code>"name": "Larry Fine"</code>.
     * 
     * @param bean
     *            An object that has getter methods that should be used to make
     *            a JSONObject.
     */
    public JSONObject(Object bean) {
        this();
        populateInternalMap(bean, false);
    }

    /**
     * Construct JSONObject from the given bean. This will also create
     * JSONObject for all internal object (List, Map, Inner Objects) of the
     * provided bean.
     * 
     * -- See Documentation of JSONObject(Object bean) also.
     * 
     * @param bean
     *            An object that has getter methods that should be used to make
     *            a JSONObject.
     * @param includeSuperClass
     *            - Tell whether to include the super class properties.
     */
    public JSONObject(Object bean, boolean includeSuperClass) {
        this();
        populateInternalMap(bean, includeSuperClass);
    }

    private void populateInternalMap(Object bean, boolean includeSuperClass) {
        Class klass = bean.getClass();

        // If klass.getSuperClass is System class then includeSuperClass =
        // false;

        if (klass.getClassLoader() == null) {
            includeSuperClass = false;
        }

        Method[] methods = (includeSuperClass) ? klass.getMethods() : klass
                .getDeclaredMethods();
        for (int i = 0; i < methods.length; i += 1) {
            try {
                Method method = methods[i];
                String name = method.getName();
                String key = "";
                if (name.startsWith("get")) {
                    key = name.substring(3);
                } else if (name.startsWith("is")) {
                    key = name.substring(2);
                }
                if (key.length() > 0 && Character.isUpperCase(key.charAt(0))
                        && method.getParameterTypes().length == 0) {
                    if (key.length() == 1) {
                        key = key.toLowerCase();
                    } else if (!Character.isUpperCase(key.charAt(1))) {
                        key = key.substring(0, 1).toLowerCase()
                                + key.substring(1);
                    }

                    Object result = method.invoke(bean, (Object[]) null);
                    if (result == null) {
                        map.put(key, NULL);
                    } else if (result.getClass().isArray()) {
                        map.put(key, new JSONArray(result, includeSuperClass));
                    } else if (result instanceof Collection) { // List or Set
                        map.put(key, new JSONArray((Collection) result,
                                includeSuperClass));
                    } else if (result instanceof Map) {
                        map.put(key, new JSONObject((Map) result,
                                includeSuperClass));
                    } else if (isStandardProperty(result.getClass())) { // Primitives,
                                                                        // String
                                                                        // and
                                                                        // Wrapper
                        map.put(key, result);
                    } else {
                        if (result.getClass().getPackage().getName()
                                .startsWith("java")
                                || result.getClass().getClassLoader() == null) {
                            map.put(key, result.toString());
                        } else { // User defined Objects
                            map.put(key, new JSONObject(result,
                                    includeSuperClass));
                        }
                    }
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    private boolean isStandardProperty(Class clazz) {
        return clazz.isPrimitive() || clazz.isAssignableFrom(Byte.class)
                || clazz.isAssignableFrom(Short.class)
                || clazz.isAssignableFrom(Integer.class)
                || clazz.isAssignableFrom(Long.class)
                || clazz.isAssignableFrom(Float.class)
                || clazz.isAssignableFrom(Double.class)
                || clazz.isAssignableFrom(Character.class)
                || clazz.isAssignableFrom(String.class)
                || clazz.isAssignableFrom(Boolean.class);
    }

    /**
     * Construct a JSONObject from an Object, using reflection to find the
     * public members. The resulting JSONObject's keys will be the strings from
     * the names array, and the values will be the field values associated with
     * those keys in the object. If a key is not found or not visible, then it
     * will not be copied into the new JSONObject.
     * 
     * @param object
     *            An object that has fields that should be used to make a
     *            JSONObject.
     * @param names
     *            An array of strings, the names of the fields to be obtained
     *            from the object.
     */
    public JSONObject(Object object, String names[]) {
        this();
        Class c = object.getClass();
        for (int i = 0; i < names.length; i += 1) {
            String name = names[i];
            try {
                putOpt(name, c.getField(name).get(object));
            } catch (Exception e) {
                /* forget about it */
            }
        }
    }

    /**
     * Construct a JSONObject from a source JSON text string. This is the most
     * commonly used JSONObject constructor.
     * 
     * @param source
     *            A string beginning with <code>{</code>&nbsp;<small>(left
     *            brace)</small> and ending with <code>}</code>
     *            &nbsp;<small>(right brace)</small>.
     * @exception JSONException
     *                If there is a syntax error in the source string or a
     *                duplicated key.
     */
    public JSONObject(String source) throws JSONException {
        this(new JSONTokener(source));
    }

    /**
     * Accumulate values under a key. It is similar to the put method except
     * that if there is already an object stored under the key then a JSONArray
     * is stored under the key to hold all of the accumulated values. If there
     * is already a JSONArray, then the new value is appended to it. In
     * contrast, the put method replaces the previous value.
     * 
     * @param key
     *            A key string.
     * @param value
     *            An object to be accumulated under the key.
     * @return this.
     * @throws JSONException
     *             If the value is an invalid number or if the key is null.
     */
    public JSONObject accumulate(String key, Object value) throws JSONException {
        testValidity(value);
        Object o = opt(key);
        if (o == null) {
            put(key, value instanceof JSONArray ? new JSONArray().put(value)
                    : value);
        } else if (o instanceof JSONArray) {
            ((JSONArray) o).put(value);
        } else {
            put(key, new JSONArray().put(o).put(value));
        }
        return this;
    }

    /**
     * Append values to the array under a key. If the key does not exist in the
     * JSONObject, then the key is put in the JSONObject with its value being a
     * JSONArray containing the value parameter. If the key was already
     * associated with a JSONArray, then the value parameter is appended to it.
     * 
     * @param key
     *            A key string.
     * @param value
     *            An object to be accumulated under the key.
     * @return this.
     * @throws JSONException
     *             If the key is null or if the current value associated with
     *             the key is not a JSONArray.
     */
    public JSONObject append(String key, Object value) throws JSONException {
        testValidity(value);
        Object o = opt(key);
        if (o == null) {
            put(key, new JSONArray().put(value));
        } else if (o instanceof JSONArray) {
            put(key, ((JSONArray) o).put(value));
        } else {
            throw new JSONException("JSONObject[" + key
                    + "] is not a JSONArray.");
        }
        return this;
    }

    /**
     * Produce a string from a double. The string "null" will be returned if the
     * number is not finite.
     * 
     * @param d
     *            A double.
     * @return A String.
     */
    static public String doubleToString(double d) {
        if (Double.isInfinite(d) || Double.isNaN(d)) {
            return "null";
        }

        // Shave off trailing zeros and decimal point, if possible.

        String s = Double.toString(d);
        if (s.indexOf('.') > 0 && s.indexOf('e') < 0 && s.indexOf('E') < 0) {
            while (s.endsWith("0")) {
                s = s.substring(0, s.length() - 1);
            }
            if (s.endsWith(".")) {
                s = s.substring(0, s.length() - 1);
            }
        }
        return s;
    }

    /**
     * Get the value object associated with a key.
     * 
     * @param key
     *            A key string.
     * @return The object associated with the key.
     * @throws JSONException
     *             if the key is not found.
     */
    /* modify by sycheng allow return null */
    public Object get(String key) throws JSONException {
        return opt(key);
        /*
         * if (o == null) { throw new JSONException("JSONObject[" + quote(key) +
         * "] not found."); } return o;
         */
    }

    /**
     * Get the boolean value associated with a key.
     * 
     * @param key
     *            A key string.
     * @return The truth.
     * @throws JSONException
     *             if the value is not a Boolean or the String "true" or
     *             "false".
     */
    public boolean getBoolean(String key) throws JSONException {
        Object o = get(key);
        if (o == null)
            return false;
        if (o.equals(Boolean.FALSE)
                || (o instanceof String && ((String) o)
                        .equalsIgnoreCase("false"))) {
            return false;
        } else if (o.equals(Boolean.TRUE)
                || (o instanceof String && ((String) o)
                        .equalsIgnoreCase("true"))) {
            return true;
        }
        throw new JSONException("JSONObject[" + quote(key)
                + "] is not a Boolean.");
    }

    /**
     * Get the double value associated with a key.
     * 
     * @param key
     *            A key string.
     * @return The numeric value.
     * @throws JSONException
     *             if the key is not found or if the value is not a Number
     *             object and cannot be converted to a number.
     */
    public double getDouble(String key) throws JSONException {
        Object o = get(key);
        if (o == null)
            return 0;
        try {
            if (o instanceof Number) {
                return ((Number) o).doubleValue();
            } else if (o.toString().length() > 0) {
                return Double.valueOf((o.toString()));
            } else
                return 0;
        } catch (Exception e) {
            throw new JSONException("JSONObject[" + quote(key)
                    + "] is not a number.");
        }
    }

    /**
     * Get the int value associated with a key. If the number value is too large
     * for an int, it will be clipped.
     * 
     * @param key
     *            A key string.
     * @return The integer value.
     * @throws JSONException
     *             if the key is not found or if the value cannot be converted
     *             to an integer.
     */
    public int getInt(String key) throws JSONException {
        Object o = get(key);
        if (o == null)
            return 0;
        return o instanceof Number ? ((Number) o).intValue()
                : (int) getDouble(key);
    }

    /**
     * Get the JSONArray value associated with a key.
     * 
     * @param key
     *            A key string.
     * @return A JSONArray which is the value.
     * @throws JSONException
     *             if the key is not found or if the value is not a JSONArray.
     */
    public JSONArray getJSONArray(String key) throws JSONException {
        Object o = get(key);
        if (o == null)
            return null;
        if (o instanceof JSONArray) {
            return (JSONArray) o;
        }
        throw new JSONException("JSONObject[" + quote(key)
                + "] is not a JSONArray.");
    }

    /**
     * Get the JSONObject value associated with a key.
     * 
     * @param key
     *            A key string.
     * @return A JSONObject which is the value.
     * @throws JSONException
     *             if the key is not found or if the value is not a JSONObject.
     */
    public JSONObject getJSONObject(String key) throws JSONException {
        Object o = get(key);
        if (o == null)
            return null;
        if (o instanceof JSONObject) {
            return (JSONObject) o;
        }
        throw new JSONException("JSONObject[" + quote(key)
                + "] is not a JSONObject.");
    }

    /**
     * Get the long value associated with a key. If the number value is too long
     * for a long, it will be clipped.
     * 
     * @param key
     *            A key string.
     * @return The long value.
     * @throws JSONException
     *             if the key is not found or if the value cannot be converted
     *             to a long.
     */
    public long getLong(String key) throws JSONException {
        Object o = get(key);

        if (o == null)
            return 0;
        if (o instanceof String) {
            if (o.toString().length() > 0) {
                return Long.valueOf((o.toString()));
            } else
                return 0;
        }
        return o instanceof Number ? ((Number) o).longValue()
                : (long) getDouble(key);
    }

    /**
     * Get an array of field names from a JSONObject.
     * 
     * @return An array of field names, or null if there are no names.
     */
    public static String[] getNames(JSONObject jo) {
        int length = jo.length();
        if (length == 0) {
            return null;
        }
        Iterator i = jo.keys();
        String[] names = new String[length];
        int j = 0;
        while (i.hasNext()) {
            names[j] = (String) i.next();
            j += 1;
        }
        return names;
    }

    /**
     * Get an array of field names from an Object.
     * 
     * @return An array of field names, or null if there are no names.
     */
    public static String[] getNames(Object object) {
        if (object == null) {
            return null;
        }
        Class klass = object.getClass();
        Field[] fields = klass.getFields();
        int length = fields.length;
        if (length == 0) {
            return null;
        }
        String[] names = new String[length];
        for (int i = 0; i < length; i += 1) {
            names[i] = fields[i].getName();
        }
        return names;
    }

    /**
     * Get the string associated with a key.
     * 
     * @param key
     *            A key string.
     * @return A string which is the value.
     * @throws JSONException
     *             if the key is not found.
     */
    public String getString(String key) throws JSONException {
        Object o = get(key);
        if (o == null)
            return "";
        return o.toString();
    }

    /**
     * Determine if the JSONObject contains a specific key.
     * 
     * @param key
     *            A key string.
     * @return true if the key exists in the JSONObject.
     */
    public boolean has(String key) {
        return this.map.containsKey(key);
    }

    /**
     * Determine if the value associated with the key is null or if there is no
     * value.
     * 
     * @param key
     *            A key string.
     * @return true if there is no value associated with the key or if the value
     *         is the JSONObject.NULL object.
     */
    public boolean isNull(String key) {
        return JSONObject.NULL.equals(opt(key));
    }

    /**
     * Get an enumeration of the keys of the JSONObject.
     * 
     * @return An iterator of the keys.
     */
    public Iterator keys() {
        return this.map.keySet().iterator();
    }

    /**
     * Get the number of keys stored in the JSONObject.
     * 
     * @return The number of keys in the JSONObject.
     */
    public int length() {
        return this.map.size();
    }

    /**
     * Produce a JSONArray containing the names of the elements of this
     * JSONObject.
     * 
     * @return A JSONArray containing the key strings, or null if the JSONObject
     *         is empty.
     */
    public JSONArray names() {
        JSONArray ja = new JSONArray();
        Iterator keys = keys();
        while (keys.hasNext()) {
            ja.put(keys.next());
        }
        return ja.length() == 0 ? null : ja;
    }

    /**
     * Produce a string from a Number.
     * 
     * @param n
     *            A Number
     * @return A String.
     * @throws JSONException
     *             If n is a non-finite number.
     */
    static public String numberToString(Number n) throws JSONException {
        if (n == null) {
            throw new JSONException("Null pointer");
        }
        testValidity(n);

        // Shave off trailing zeros and decimal point, if possible.

        String s = n.toString();
        if (s.indexOf('.') > 0 && s.indexOf('e') < 0 && s.indexOf('E') < 0) {
            while (s.endsWith("0")) {
                s = s.substring(0, s.length() - 1);
            }
            if (s.endsWith(".")) {
                s = s.substring(0, s.length() - 1);
            }
        }
        return s;
    }

    /**
     * Get an optional value associated with a key.
     * 
     * @param key
     *            A key string.
     * @return An object which is the value, or null if there is no value.
     */
    public Object opt(String key) {
        return key == null ? null : this.map.get(key);
    }

    /**
     * Get an optional boolean associated with a key. It returns false if there
     * is no such key, or if the value is not Boolean.TRUE or the String "true".
     * 
     * @param key
     *            A key string.
     * @return The truth.
     */
    public boolean optBoolean(String key) {
        return optBoolean(key, false);
    }

    /**
     * Get an optional boolean associated with a key. It returns the
     * defaultValue if there is no such key, or if it is not a Boolean or the
     * String "true" or "false" (case insensitive).
     * 
     * @param key
     *            A key string.
     * @param defaultValue
     *            The default.
     * @return The truth.
     */
    public boolean optBoolean(String key, boolean defaultValue) {
        try {
            return getBoolean(key);
        } catch (Exception e) {
            return defaultValue;
        }
    }

    /**
     * Put a key/value pair in the JSONObject, where the value will be a
     * JSONArray which is produced from a Collection.
     * 
     * @param key
     *            A key string.
     * @param value
     *            A Collection value.
     * @return this.
     * @throws JSONException
     */
    public JSONObject put(String key, Collection value) throws JSONException {
        put(key, new JSONArray(value));
        return this;
    }

    /**
     * Get an optional double associated with a key, or NaN if there is no such
     * key or if its value is not a number. If the value is a string, an attempt
     * will be made to evaluate it as a number.
     * 
     * @param key
     *            A string which is the key.
     * @return An object which is the value.
     */
    public double optDouble(String key) {
        return optDouble(key, Double.NaN);
    }

    /**
     * Get an optional double associated with a key, or the defaultValue if
     * there is no such key or if its value is not a number. If the value is a
     * string, an attempt will be made to evaluate it as a number.
     * 
     * @param key
     *            A key string.
     * @param defaultValue
     *            The default.
     * @return An object which is the value.
     */
    public double optDouble(String key, double defaultValue) {
        try {
            Object o = opt(key);
            return o instanceof Number ? ((Number) o).doubleValue()
                    : new Double((String) o).doubleValue();
        } catch (Exception e) {
            return defaultValue;
        }
    }

    /**
     * Get an optional int value associated with a key, or zero if there is no
     * such key or if the value is not a number. If the value is a string, an
     * attempt will be made to evaluate it as a number.
     * 
     * @param key
     *            A key string.
     * @return An object which is the value.
     */
    public int optInt(String key) {
        return optInt(key, 0);
    }

    /**
     * Get an optional int value associated with a key, or the default if there
     * is no such key or if the value is not a number. If the value is a string,
     * an attempt will be made to evaluate it as a number.
     * 
     * @param key
     *            A key string.
     * @param defaultValue
     *            The default.
     * @return An object which is the value.
     */
    public int optInt(String key, int defaultValue) {
        try {
            return getInt(key);
        } catch (Exception e) {
            return defaultValue;
        }
    }

    /**
     * Get an optional JSONArray associated with a key. It returns null if there
     * is no such key, or if its value is not a JSONArray.
     * 
     * @param key
     *            A key string.
     * @return A JSONArray which is the value.
     */
    public JSONArray optJSONArray(String key) {
        Object o = opt(key);
        return o instanceof JSONArray ? (JSONArray) o : null;
    }

    /**
     * Get an optional JSONObject associated with a key. It returns null if
     * there is no such key, or if its value is not a JSONObject.
     * 
     * @param key
     *            A key string.
     * @return A JSONObject which is the value.
     */
    public JSONObject optJSONObject(String key) {
        Object o = opt(key);
        return o instanceof JSONObject ? (JSONObject) o : null;
    }

    /**
     * Get an optional long value associated with a key, or zero if there is no
     * such key or if the value is not a number. If the value is a string, an
     * attempt will be made to evaluate it as a number.
     * 
     * @param key
     *            A key string.
     * @return An object which is the value.
     */
    public long optLong(String key) {
        return optLong(key, 0);
    }

    /**
     * Get an optional long value associated with a key, or the default if there
     * is no such key or if the value is not a number. If the value is a string,
     * an attempt will be made to evaluate it as a number.
     * 
     * @param key
     *            A key string.
     * @param defaultValue
     *            The default.
     * @return An object which is the value.
     */
    public long optLong(String key, long defaultValue) {
        try {
            return getLong(key);
        } catch (Exception e) {
            return defaultValue;
        }
    }

    /**
     * Get an optional string associated with a key. It returns an empty string
     * if there is no such key. If the value is not a string and is not null,
     * then it is coverted to a string.
     * 
     * @param key
     *            A key string.
     * @return A string which is the value.
     */
    public String optString(String key) {
        return optString(key, "");
    }

    /**
     * Get an optional string associated with a key. It returns the defaultValue
     * if there is no such key.
     * 
     * @param key
     *            A key string.
     * @param defaultValue
     *            The default.
     * @return A string which is the value.
     */
    public String optString(String key, String defaultValue) {
        Object o = opt(key);
        return o != null ? o.toString() : defaultValue;
    }

    /**
     * Put a key/boolean pair in the JSONObject.
     * 
     * @param key
     *            A key string.
     * @param value
     *            A boolean which is the value.
     * @return this.
     * @throws JSONException
     *             If the key is null.
     */
    public JSONObject put(String key, boolean value) throws JSONException {
        put(key, value ? Boolean.TRUE : Boolean.FALSE);
        return this;
    }

    /**
     * Put a key/double pair in the JSONObject.
     * 
     * @param key
     *            A key string.
     * @param value
     *            A double which is the value.
     * @return this.
     * @throws JSONException
     *             If the key is null or if the number is invalid.
     */
    public JSONObject put(String key, double value) throws JSONException {
        put(key, new Double(value));
        return this;
    }

    /**
     * Put a key/int pair in the JSONObject.
     * 
     * @param key
     *            A key string.
     * @param value
     *            An int which is the value.
     * @return this.
     * @throws JSONException
     *             If the key is null.
     */
    public JSONObject put(String key, int value) throws JSONException {
        put(key, new Integer(value));
        return this;
    }

    /**
     * Put a key/long pair in the JSONObject.
     * 
     * @param key
     *            A key string.
     * @param value
     *            A long which is the value.
     * @return this.
     * @throws JSONException
     *             If the key is null.
     */
    public JSONObject put(String key, long value) throws JSONException {
        put(key, new Long(value));
        return this;
    }

    /**
     * Put a key/value pair in the JSONObject, where the value will be a
     * JSONObject which is produced from a Map.
     * 
     * @param key
     *            A key string.
     * @param value
     *            A Map value.
     * @return this.
     * @throws JSONException
     */
    public JSONObject put(String key, Map value) throws JSONException {
        put(key, new JSONObject(value));
        return this;
    }

    /**
     * Put a key/value pair in the JSONObject. If the value is null, then the
     * key will be removed from the JSONObject if it is present.
     * 
     * @param key
     *            A key string.
     * @param value
     *            An object which is the value. It should be of one of these
     *            types: Boolean, Double, Integer, JSONArray, JSONObject, Long,
     *            String, or the JSONObject.NULL object.
     * @return this.
     * @throws JSONException
     *             If the value is non-finite number or if the key is null.
     */
    public JSONObject put(String key, Object value) throws JSONException {
        if (key == null) {
            throw new JSONException("Null key.");
        }
        if (value != null) {
            testValidity(value);
            this.map.put(key, value);
        } else {
            remove(key);
        }
        return this;
    }

    /**
     * Put a key/value pair in the JSONObject, but only if the key and the value
     * are both non-null, and only if there is not already a member with that
     * name.
     * 
     * @param key
     * @param value
     * @return his.
     * @throws JSONException
     *             if the key is a duplicate
     */
    public JSONObject putOnce(String key, Object value) throws JSONException {
        if (key != null && value != null) {
            if (opt(key) != null) {
                throw new JSONException("Duplicate key \"" + key + "\"");
            }
            put(key, value);
        }
        return this;
    }

    /**
     * Put a key/value pair in the JSONObject, but only if the key and the value
     * are both non-null.
     * 
     * @param key
     *            A key string.
     * @param value
     *            An object which is the value. It should be of one of these
     *            types: Boolean, Double, Integer, JSONArray, JSONObject, Long,
     *            String, or the JSONObject.NULL object.
     * @return this.
     * @throws JSONException
     *             If the value is a non-finite number.
     */
    public JSONObject putOpt(String key, Object value) throws JSONException {
        if (key != null && value != null) {
            put(key, value);
        }
        return this;
    }

    /**
     * Produce a string in double quotes with backslash sequences in all the
     * right places. A backslash will be inserted within </, allowing JSON text
     * to be delivered in HTML. In JSON text, a string cannot contain a control
     * character or an unescaped quote or backslash.
     * 
     * @param string
     *            A String
     * @return A String correctly formatted for insertion in a JSON text.
     */
    public static String quote(String string) {
        if (string == null || string.length() == 0) {
            return "\"\"";
        }

        char b;
        char c = 0;
        int i;
        int len = string.length();
        StringBuffer sb = new StringBuffer(len + 4);
        String t;

        sb.append('"');
        for (i = 0; i < len; i += 1) {
            b = c;
            c = string.charAt(i);
            switch (c) {
            case '\\':
            case '"':
                sb.append('\\');
                sb.append(c);
                break;
            case '/':
                if (b == '<') {
                    sb.append('\\');
                }
                sb.append(c);
                break;
            case '\b':
                sb.append("\\b");
                break;
            case '\t':
                sb.append("\\t");
                break;
            case '\n':
                sb.append("\\n");
                break;
            case '\f':
                sb.append("\\f");
                break;
            case '\r':
                sb.append("\\r");
                break;
            default:
                if (c < ' ' || (c >= '\u0080' && c < '\u00a0')
                        || (c >= '\u2000' && c < '\u2100')) {
                    t = "000" + Integer.toHexString(c);
                    sb.append("\\u" + t.substring(t.length() - 4));
                } else {
                    sb.append(c);
                }
            }
        }
        sb.append('"');
        return sb.toString();
    }

    /**
     * Remove a name and its value, if present.
     * 
     * @param key
     *            The name to be removed.
     * @return The value that was associated with the name, or null if there was
     *         no value.
     */
    public Object remove(String key) {
        return this.map.remove(key);
    }

    /**
     * Get an enumeration of the keys of the JSONObject. The keys will be sorted
     * alphabetically.
     * 
     * @return An iterator of the keys.
     */
    public Iterator sortedKeys() {
        return new TreeSet(this.map.keySet()).iterator();
    }

    /**
     * Try to convert a string into a number, boolean, or null. If the string
     * can't be converted, return the string.
     * 
     * @param s
     *            A String.
     * @return A simple JSON value.
     */
    static public Object stringToValue(String s) {
        if (s.equals("")) {
            return s;
        }
        if (s.equalsIgnoreCase("true")) {
            return Boolean.TRUE;
        }
        if (s.equalsIgnoreCase("false")) {
            return Boolean.FALSE;
        }
        if (s.equalsIgnoreCase("null")) {
            return JSONObject.NULL;
        }

        /*
         * If it might be a number, try converting it. We support the 0- and 0x-
         * conventions. If a number cannot be produced, then the value will just
         * be a string. Note that the 0-, 0x-, plus, and implied string
         * conventions are non-standard. A JSON parser is free to accept
         * non-JSON forms as long as it accepts all correct JSON forms.
         */

        char b = s.charAt(0);
        if ((b >= '0' && b <= '9') || b == '.' || b == '-' || b == '+') {
            if (b == '0') {
                if (s.length() > 2
                        && (s.charAt(1) == 'x' || s.charAt(1) == 'X')) {
                    try {
                        return new Integer(Integer.parseInt(s.substring(2), 16));
                    } catch (Exception e) {
                        /* Ignore the error */
                    }
                } else {
                    try {
                        return new Integer(Integer.parseInt(s, 8));
                    } catch (Exception e) {
                        /* Ignore the error */
                    }
                }
            }
            try {
                return new Integer(s);
            } catch (Exception e) {
                try {
                    return new Long(s);
                } catch (Exception f) {
                    try {
                        return new Double(s);
                    } catch (Exception g) {
                        /* Ignore the error */
                    }
                }
            }
        }
        return s;
    }

    /**
     * Throw an exception if the object is an NaN or infinite number.
     * 
     * @param o
     *            The object to test.
     * @throws JSONException
     *             If o is a non-finite number.
     */
    static void testValidity(Object o) throws JSONException {
        if (o != null) {
            if (o instanceof Double) {
                if (((Double) o).isInfinite() || ((Double) o).isNaN()) {
                    throw new JSONException(
                            "JSON does not allow non-finite numbers.");
                }
            } else if (o instanceof Float) {
                if (((Float) o).isInfinite() || ((Float) o).isNaN()) {
                    throw new JSONException(
                            "JSON does not allow non-finite numbers.");
                }
            }
        }
    }

    /**
     * Produce a JSONArray containing the values of the members of this
     * JSONObject.
     * 
     * @param names
     *            A JSONArray containing a list of key strings. This determines
     *            the sequence of the values in the result.
     * @return A JSONArray of values.
     * @throws JSONException
     *             If any of the values are non-finite numbers.
     */
    public JSONArray toJSONArray(JSONArray names) throws JSONException {
        if (names == null || names.length() == 0) {
            return null;
        }
        JSONArray ja = new JSONArray();
        for (int i = 0; i < names.length(); i += 1) {
            ja.put(this.opt(names.getString(i)));
        }
        return ja;
    }

    /**
     * Make a JSON text of this JSONObject. For compactness, no whitespace is
     * added. If this would not result in a syntactically correct JSON text,
     * then null will be returned instead.
     * <p>
     * Warning: This method assumes that the data structure is acyclical.
     * 
     * @return a printable, displayable, portable, transmittable representation
     *         of the object, beginning with <code>{</code>&nbsp;<small>(left
     *         brace)</small> and ending with <code>}</code>&nbsp;<small>(right
     *         brace)</small>.
     */
    public String toString() {
        try {
            Iterator keys = keys();
            StringBuffer sb = new StringBuffer("{");

            while (keys.hasNext()) {
                if (sb.length() > 1) {
                    sb.append(',');
                }
                Object o = keys.next();
                sb.append(quote(o.toString()));
                sb.append(':');
                sb.append(valueToString(this.map.get(o)));
            }
            sb.append('}');
            return sb.toString();
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * Make a prettyprinted JSON text of this JSONObject.
     * <p>
     * Warning: This method assumes that the data structure is acyclical.
     * 
     * @param indentFactor
     *            The number of spaces to add to each level of indentation.
     * @return a printable, displayable, portable, transmittable representation
     *         of the object, beginning with <code>{</code>&nbsp;<small>(left
     *         brace)</small> and ending with <code>}</code>&nbsp;<small>(right
     *         brace)</small>.
     * @throws JSONException
     *             If the object contains an invalid number.
     */
    public String toString(int indentFactor) throws JSONException {
        return toString(indentFactor, 0);
    }

    /**
     * Make a prettyprinted JSON text of this JSONObject.
     * <p>
     * Warning: This method assumes that the data structure is acyclical.
     * 
     * @param indentFactor
     *            The number of spaces to add to each level of indentation.
     * @param indent
     *            The indentation of the top level.
     * @return a printable, displayable, transmittable representation of the
     *         object, beginning with <code>{</code>&nbsp;<small>(left
     *         brace)</small> and ending with <code>}</code>&nbsp;<small>(right
     *         brace)</small>.
     * @throws JSONException
     *             If the object contains an invalid number.
     */
    String toString(int indentFactor, int indent) throws JSONException {
        int j;
        int n = length();
        if (n == 0) {
            return "{}";
        }
        Iterator keys = sortedKeys();
        StringBuffer sb = new StringBuffer("{");
        int newindent = indent + indentFactor;
        Object o;
        if (n == 1) {
            o = keys.next();
            sb.append(quote(o.toString()));
            sb.append(": ");
            sb.append(valueToString(this.map.get(o), indentFactor, indent));
        } else {
            while (keys.hasNext()) {
                o = keys.next();
                if (sb.length() > 1) {
                    sb.append(",\n");
                } else {
                    sb.append('\n');
                }
                for (j = 0; j < newindent; j += 1) {
                    sb.append(' ');
                }
                sb.append(quote(o.toString()));
                sb.append(": ");
                sb.append(valueToString(this.map.get(o), indentFactor,
                        newindent));
            }
            if (sb.length() > 1) {
                sb.append('\n');
                for (j = 0; j < indent; j += 1) {
                    sb.append(' ');
                }
            }
        }
        sb.append('}');
        return sb.toString();
    }

    /**
     * Make a JSON text of an Object value. If the object has an
     * value.toJSONString() method, then that method will be used to produce the
     * JSON text. The method is required to produce a strictly conforming text.
     * If the object does not contain a toJSONString method (which is the most
     * common case), then a text will be produced by other means. If the value
     * is an array or Collection, then a JSONArray will be made from it and its
     * toJSONString method will be called. If the value is a MAP, then a
     * JSONObject will be made from it and its toJSONString method will be
     * called. Otherwise, the value's toString method will be called, and the
     * result will be quoted.
     * 
     * <p>
     * Warning: This method assumes that the data structure is acyclical.
     * 
     * @param value
     *            The value to be serialized.
     * @return a printable, displayable, transmittable representation of the
     *         object, beginning with <code>{</code>&nbsp;<small>(left
     *         brace)</small> and ending with <code>}</code>&nbsp;<small>(right
     *         brace)</small>.
     * @throws JSONException
     *             If the value is or contains an invalid number.
     */
    static String valueToString(Object value) throws JSONException {
        if (value == null || value.equals(null)) {
            return "null";
        }
        if (value instanceof JSONString) {
            Object o;
            try {
                o = ((JSONString) value).toJSONString();
            } catch (Exception e) {
                throw new JSONException(e);
            }
            if (o instanceof String) {
                return (String) o;
            }
            throw new JSONException("Bad value from toJSONString: " + o);
        }
        if (value instanceof Number) {
            return numberToString((Number) value);
        }
        if (value instanceof Boolean || value instanceof JSONObject
                || value instanceof JSONArray) {
            return value.toString();
        }
        if (value instanceof Map) {
            return new JSONObject((Map) value).toString();
        }
        if (value instanceof Collection) {
            return new JSONArray((Collection) value).toString();
        }
        if (value.getClass().isArray()) {
            return new JSONArray(value).toString();
        }
        return quote(value.toString());
    }

    /**
     * Make a prettyprinted JSON text of an object value.
     * <p>
     * Warning: This method assumes that the data structure is acyclical.
     * 
     * @param value
     *            The value to be serialized.
     * @param indentFactor
     *            The number of spaces to add to each level of indentation.
     * @param indent
     *            The indentation of the top level.
     * @return a printable, displayable, transmittable representation of the
     *         object, beginning with <code>{</code>&nbsp;<small>(left
     *         brace)</small> and ending with <code>}</code>&nbsp;<small>(right
     *         brace)</small>.
     * @throws JSONException
     *             If the object contains an invalid number.
     */
    static String valueToString(Object value, int indentFactor, int indent)
            throws JSONException {
        if (value == null || value.equals(null)) {
            return "null";
        }
        try {
            if (value instanceof JSONString) {
                Object o = ((JSONString) value).toJSONString();
                if (o instanceof String) {
                    return (String) o;
                }
            }
        } catch (Exception e) {
            /* forget about it */
        }
        if (value instanceof Number) {
            return numberToString((Number) value);
        }
        if (value instanceof Boolean) {
            return value.toString();
        }
        if (value instanceof JSONObject) {
            return ((JSONObject) value).toString(indentFactor, indent);
        }
        if (value instanceof JSONArray) {
            return ((JSONArray) value).toString(indentFactor, indent);
        }
        if (value instanceof Map) {
            return new JSONObject((Map) value).toString(indentFactor, indent);
        }
        if (value instanceof Collection) {
            return new JSONArray((Collection) value).toString(indentFactor,
                    indent);
        }
        if (value.getClass().isArray()) {
            return new JSONArray(value).toString(indentFactor, indent);
        }
        return quote(value.toString());
    }

    /**
     * Write the contents of the JSONObject as JSON text to a writer. For
     * compactness, no whitespace is added.
     * <p>
     * Warning: This method assumes that the data structure is acyclical.
     * 
     * @return The writer.
     * @throws JSONException
     */
    public Writer write(Writer writer) throws JSONException {
        try {
            boolean b = false;
            Iterator keys = keys();
            writer.write('{');

            while (keys.hasNext()) {
                if (b) {
                    writer.write(',');
                }
                Object k = keys.next();
                writer.write(quote(k.toString()));
                writer.write(':');
                Object v = this.map.get(k);
                if (v instanceof JSONObject) {
                    ((JSONObject) v).write(writer);
                } else if (v instanceof JSONArray) {
                    ((JSONArray) v).write(writer);
                } else {
                    writer.write(valueToString(v));
                }
                b = true;
            }
            writer.write('}');
            return writer;
        } catch (IOException e) {
            throw new JSONException(e);
        }
    }
}

JSONString.java

package weibo4j.org.json;


public interface JSONString {

    public String toJSONString();
}

JSONStringer.java

package weibo4j.org.json;


import java.io.StringWriter;


public class JSONStringer extends JSONWriter {

    public JSONStringer() {
        super(new StringWriter());
    }


    public String toString() {
        return this.mode == 'd' ? this.writer.toString() : null;
    }
}

JSONTokener.java

package weibo4j.org.json;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;


public class JSONTokener {

    private int index;
    private Reader reader;
    private char lastChar;
    private boolean useLastChar;

    /**
     * Construct a JSONTokener from a string.
     * 
     * @param reader
     *            A reader.
     */
    public JSONTokener(Reader reader) {
        this.reader = reader.markSupported() ? reader : new BufferedReader(
                reader);
        this.useLastChar = false;
        this.index = 0;
    }

    /**
     * Construct a JSONTokener from a string.
     * 
     * @param s
     *            A source string.
     */
    public JSONTokener(String s) {
        this(new StringReader(s));
    }

    /**
     * Back up one character. This provides a sort of lookahead capability, so
     * that you can test for a digit or letter before attempting to parse the
     * next number or identifier.
     */
    public void back() throws JSONException {
        if (useLastChar || index <= 0) {
            throw new JSONException("Stepping back two steps is not supported");
        }
        index -= 1;
        useLastChar = true;
    }

    /**
     * Get the hex value of a character (base16).
     * 
     * @param c
     *            A character between '0' and '9' or between 'A' and 'F' or
     *            between 'a' and 'f'.
     * @return An int between 0 and 15, or -1 if c was not a hex digit.
     */
    public static int dehexchar(char c) {
        if (c >= '0' && c <= '9') {
            return c - '0';
        }
        if (c >= 'A' && c <= 'F') {
            return c - ('A' - 10);
        }
        if (c >= 'a' && c <= 'f') {
            return c - ('a' - 10);
        }
        return -1;
    }

    /**
     * Determine if the source string still contains characters that next() can
     * consume.
     * 
     * @return true if not yet at the end of the source.
     */
    public boolean more() throws JSONException {
        char nextChar = next();
        if (nextChar == 0) {
            return false;
        }
        back();
        return true;
    }

    /**
     * Get the next character in the source string.
     * 
     * @return The next character, or 0 if past the end of the source string.
     */
    public char next() throws JSONException {
        if (this.useLastChar) {
            this.useLastChar = false;
            if (this.lastChar != 0) {
                this.index += 1;
            }
            return this.lastChar;
        }
        int c;
        try {
            c = this.reader.read();
        } catch (IOException exc) {
            throw new JSONException(exc);
        }

        if (c <= 0) { // End of stream
            this.lastChar = 0;
            return 0;
        }
        this.index += 1;
        this.lastChar = (char) c;
        return this.lastChar;
    }

    /**
     * Consume the next character, and check that it matches a specified
     * character.
     * 
     * @param c
     *            The character to match.
     * @return The character.
     * @throws JSONException
     *             if the character does not match.
     */
    public char next(char c) throws JSONException {
        char n = next();
        if (n != c) {
            throw syntaxError("Expected '" + c + "' and instead saw '" + n
                    + "'");
        }
        return n;
    }

    /**
     * Get the next n characters.
     * 
     * @param n
     *            The number of characters to take.
     * @return A string of n characters.
     * @throws JSONException
     *             Substring bounds error if there are not n characters
     *             remaining in the source string.
     */
    public String next(int n) throws JSONException {
        if (n == 0) {
            return "";
        }

        char[] buffer = new char[n];
        int pos = 0;

        if (this.useLastChar) {
            this.useLastChar = false;
            buffer[0] = this.lastChar;
            pos = 1;
        }

        try {
            int len;
            while ((pos < n)
                    && ((len = reader.read(buffer, pos, n - pos)) != -1)) {
                pos += len;
            }
        } catch (IOException exc) {
            throw new JSONException(exc);
        }
        this.index += pos;

        if (pos < n) {
            throw syntaxError("Substring bounds error");
        }

        this.lastChar = buffer[n - 1];
        return new String(buffer);
    }

    /**
     * Get the next char in the string, skipping whitespace.
     * 
     * @throws JSONException
     * @return A character, or 0 if there are no more characters.
     */
    public char nextClean() throws JSONException {
        for (;;) {
            char c = next();
            if (c == 0 || c > ' ') {
                return c;
            }
        }
    }

    /**
     * Return the characters up to the next close quote character. Backslash
     * processing is done. The formal JSON format does not allow strings in
     * single quotes, but an implementation is allowed to accept them.
     * 
     * @param quote
     *            The quoting character, either <code>"</code>
     *            &nbsp;<small>(double quote)</small> or <code>'</code>
     *            &nbsp;<small>(single quote)</small>.
     * @return A String.
     * @throws JSONException
     *             Unterminated string.
     */
    public String nextString(char quote) throws JSONException {
        char c;
        StringBuffer sb = new StringBuffer();
        for (;;) {
            c = next();
            switch (c) {
            case 0:
            case '\n':
            case '\r':
                throw syntaxError("Unterminated string");
            case '\\':
                c = next();
                switch (c) {
                case 'b':
                    sb.append('\b');
                    break;
                case 't':
                    sb.append('\t');
                    break;
                case 'n':
                    sb.append('\n');
                    break;
                case 'f':
                    sb.append('\f');
                    break;
                case 'r':
                    sb.append('\r');
                    break;
                case 'u':
                    sb.append((char) Integer.parseInt(next(4), 16));
                    break;
                case 'x':
                    sb.append((char) Integer.parseInt(next(2), 16));
                    break;
                default:
                    sb.append(c);
                }
                break;
            default:
                if (c == quote) {
                    return sb.toString();
                }
                sb.append(c);
            }
        }
    }

    /**
     * Get the text up but not including the specified character or the end of
     * line, whichever comes first.
     * 
     * @param d
     *            A delimiter character.
     * @return A string.
     */
    public String nextTo(char d) throws JSONException {
        StringBuffer sb = new StringBuffer();
        for (;;) {
            char c = next();
            if (c == d || c == 0 || c == '\n' || c == '\r') {
                if (c != 0) {
                    back();
                }
                return sb.toString().trim();
            }
            sb.append(c);
        }
    }

    /**
     * Get the text up but not including one of the specified delimiter
     * characters or the end of line, whichever comes first.
     * 
     * @param delimiters
     *            A set of delimiter characters.
     * @return A string, trimmed.
     */
    public String nextTo(String delimiters) throws JSONException {
        char c;
        StringBuffer sb = new StringBuffer();
        for (;;) {
            c = next();
            if (delimiters.indexOf(c) >= 0 || c == 0 || c == '\n' || c == '\r') {
                if (c != 0) {
                    back();
                }
                return sb.toString().trim();
            }
            sb.append(c);
        }
    }

    /**
     * Get the next value. The value can be a Boolean, Double, Integer,
     * JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object.
     * 
     * @throws JSONException
     *             If syntax error.
     * 
     * @return An object.
     */
    public Object nextValue() throws JSONException {
        char c = nextClean();
        String s;

        switch (c) {
        case '"':
        case '\'':
            return nextString(c);
        case '{':
            back();
            return new JSONObject(this);
        case '[':
        case '(':
            back();
            return new JSONArray(this);
        }

        /*
         * Handle unquoted text. This could be the values true, false, or null,
         * or it can be a number. An implementation (such as this one) is
         * allowed to also accept non-standard forms.
         * 
         * Accumulate characters until we reach the end of the text or a
         * formatting character.
         */

        StringBuffer sb = new StringBuffer();
        while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) {
            sb.append(c);
            c = next();
        }
        back();

        s = sb.toString().trim();
        if (s.equals("")) {
            throw syntaxError("Missing value");
        }
        return JSONObject.stringToValue(s);
    }

    /**
     * Skip characters until the next character is the requested character. If
     * the requested character is not found, no characters are skipped.
     * 
     * @param to
     *            A character to skip to.
     * @return The requested character, or zero if the requested character is
     *         not found.
     */
    public char skipTo(char to) throws JSONException {
        char c;
        try {
            int startIndex = this.index;
            reader.mark(Integer.MAX_VALUE);
            do {
                c = next();
                if (c == 0) {
                    reader.reset();
                    this.index = startIndex;
                    return c;
                }
            } while (c != to);
        } catch (IOException exc) {
            throw new JSONException(exc);
        }

        back();
        return c;
    }

    /**
     * Make a JSONException to signal a syntax error.
     * 
     * @param message
     *            The error message.
     * @return A JSONException object, suitable for throwing
     */
    public JSONException syntaxError(String message) {
        return new JSONException(message + toString());
    }

    /**
     * Make a printable string of this JSONTokener.
     * 
     * @return " at character [this.index]"
     */
    public String toString() {
        return " at character " + index;
    }
}

JSONWriter.java

package weibo4j.org.json;

import java.io.IOException;
import java.io.Writer;


public class JSONWriter {
    private static final int maxdepth = 20;


    private boolean comma;


    protected char mode;

    private JSONObject stack[];


    private int top;

    /**
     * The writer that will receive the output.
     */
    protected Writer writer;

    /**
     * Make a fresh JSONWriter. It can be used to build one JSON text.
     */
    public JSONWriter(Writer w) {
        this.comma = false;
        this.mode = 'i';
        this.stack = new JSONObject[maxdepth];
        this.top = 0;
        this.writer = w;
    }

    /**
     * Append a value.
     * 
     * @param s
     *            A string value.
     * @return this
     * @throws JSONException
     *             If the value is out of sequence.
     */
    private JSONWriter append(String s) throws JSONException {
        if (s == null) {
            throw new JSONException("Null pointer");
        }
        if (this.mode == 'o' || this.mode == 'a') {
            try {
                if (this.comma && this.mode == 'a') {
                    this.writer.write(',');
                }
                this.writer.write(s);
            } catch (IOException e) {
                throw new JSONException(e);
            }
            if (this.mode == 'o') {
                this.mode = 'k';
            }
            this.comma = true;
            return this;
        }
        throw new JSONException("Value out of sequence.");
    }

    /**
     * Begin appending a new array. All values until the balancing
     * <code>endArray</code> will be appended to this array. The
     * <code>endArray</code> method must be called to mark the array's end.
     * 
     * @return this
     * @throws JSONException
     *             If the nesting is too deep, or if the object is started in
     *             the wrong place (for example as a key or after the end of the
     *             outermost array or object).
     */
    public JSONWriter array() throws JSONException {
        if (this.mode == 'i' || this.mode == 'o' || this.mode == 'a') {
            this.push(null);
            this.append("[");
            this.comma = false;
            return this;
        }
        throw new JSONException("Misplaced array.");
    }

    /**
     * End something.
     * 
     * @param m
     *            Mode
     * @param c
     *            Closing character
     * @return this
     * @throws JSONException
     *             If unbalanced.
     */
    private JSONWriter end(char m, char c) throws JSONException {
        if (this.mode != m) {
            throw new JSONException(m == 'o' ? "Misplaced endObject."
                    : "Misplaced endArray.");
        }
        this.pop(m);
        try {
            this.writer.write(c);
        } catch (IOException e) {
            throw new JSONException(e);
        }
        this.comma = true;
        return this;
    }

    /**
     * End an array. This method most be called to balance calls to
     * <code>array</code>.
     * 
     * @return this
     * @throws JSONException
     *             If incorrectly nested.
     */
    public JSONWriter endArray() throws JSONException {
        return this.end('a', ']');
    }

    /**
     * End an object. This method most be called to balance calls to
     * <code>object</code>.
     * 
     * @return this
     * @throws JSONException
     *             If incorrectly nested.
     */
    public JSONWriter endObject() throws JSONException {
        return this.end('k', '}');
    }

    /**
     * Append a key. The key will be associated with the next value. In an
     * object, every value must be preceded by a key.
     * 
     * @param s
     *            A key string.
     * @return this
     * @throws JSONException
     *             If the key is out of place. For example, keys do not belong
     *             in arrays or if the key is null.
     */
    public JSONWriter key(String s) throws JSONException {
        if (s == null) {
            throw new JSONException("Null key.");
        }
        if (this.mode == 'k') {
            try {
                if (this.comma) {
                    this.writer.write(',');
                }
                stack[top - 1].putOnce(s, Boolean.TRUE);
                this.writer.write(JSONObject.quote(s));
                this.writer.write(':');
                this.comma = false;
                this.mode = 'o';
                return this;
            } catch (IOException e) {
                throw new JSONException(e);
            }
        }
        throw new JSONException("Misplaced key.");
    }

    /**
     * Begin appending a new object. All keys and values until the balancing
     * <code>endObject</code> will be appended to this object. The
     * <code>endObject</code> method must be called to mark the object's end.
     * 
     * @return this
     * @throws JSONException
     *             If the nesting is too deep, or if the object is started in
     *             the wrong place (for example as a key or after the end of the
     *             outermost array or object).
     */
    public JSONWriter object() throws JSONException {
        if (this.mode == 'i') {
            this.mode = 'o';
        }
        if (this.mode == 'o' || this.mode == 'a') {
            this.append("{");
            this.push(new JSONObject());
            this.comma = false;
            return this;
        }
        throw new JSONException("Misplaced object.");

    }

    /**
     * Pop an array or object scope.
     * 
     * @param c
     *            The scope to close.
     * @throws JSONException
     *             If nesting is wrong.
     */
    private void pop(char c) throws JSONException {
        if (this.top <= 0) {
            throw new JSONException("Nesting error.");
        }
        char m = this.stack[this.top - 1] == null ? 'a' : 'k';
        if (m != c) {
            throw new JSONException("Nesting error.");
        }
        this.top -= 1;
        this.mode = this.top == 0 ? 'd'
                : this.stack[this.top - 1] == null ? 'a' : 'k';
    }

    /**
     * Push an array or object scope.
     * 
     * @param c
     *            The scope to open.
     * @throws JSONException
     *             If nesting is too deep.
     */
    private void push(JSONObject jo) throws JSONException {
        if (this.top >= maxdepth) {
            throw new JSONException("Nesting too deep.");
        }
        this.stack[this.top] = jo;
        this.mode = jo == null ? 'a' : 'k';
        this.top += 1;
    }

    /**
     * Append either the value <code>true</code> or the value <code>false</code>
     * .
     * 
     * @param b
     *            A boolean.
     * @return this
     * @throws JSONException
     */
    public JSONWriter value(boolean b) throws JSONException {
        return this.append(b ? "true" : "false");
    }

    /**
     * Append a double value.
     * 
     * @param d
     *            A double.
     * @return this
     * @throws JSONException
     *             If the number is not finite.
     */
    public JSONWriter value(double d) throws JSONException {
        return this.value(new Double(d));
    }

    /**
     * Append a long value.
     * 
     * @param l
     *            A long.
     * @return this
     * @throws JSONException
     */
    public JSONWriter value(long l) throws JSONException {
        return this.append(Long.toString(l));
    }

    /**
     * Append an object value.
     * 
     * @param o
     *            The object to append. It can be null, or a Boolean, Number,
     *            String, JSONObject, or JSONArray, or an object with a
     *            toJSONString() method.
     * @return this
     * @throws JSONException
     *             If the value is out of sequence.
     */
    public JSONWriter value(Object o) throws JSONException {
        return this.append(JSONObject.valueToString(o));
    }
}

weibo4j.util包

BareBonesBrowserLaunch.java

package weibo4j.util;

/////////////////////////////////////////////////////////
//Bare Bones Browser Launch                            //
//Version 1.5 (December 10, 2005)                      //
//By Dem Pilafian                                      //
//Supports: Mac OS X, GNU/Linux, Unix, Windows XP      //
//Example Usage:                                       //
// String url = "http://www.centerkey.com/";           //
// BareBonesBrowserLaunch.openURL(url);                //
//Public Domain Software -- Free to Use as You Like    //
/////////////////////////////////////////////////////////

/**
 * @author Dem Pilafian
 * @author John Kristian
 */
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import javax.swing.JOptionPane;

public class BareBonesBrowserLaunch {

    public static void openURL(String url) {
        try {
            browse(url);
        } catch (Exception e) {
            JOptionPane.showMessageDialog(
                    null,
                    "Error attempting to launch web browser:\n"
                            + e.getLocalizedMessage());
        }
    }

    private static void browse(String url) throws ClassNotFoundException,
            IllegalAccessException, IllegalArgumentException,
            InterruptedException, InvocationTargetException, IOException,
            NoSuchMethodException {
        String osName = System.getProperty("os.name", "");
        if (osName.startsWith("Mac OS")) {
            Class fileMgr = Class.forName("com.apple.eio.FileManager");
            Method openURL = fileMgr.getDeclaredMethod("openURL",
                    new Class[] { String.class });
            openURL.invoke(null, new Object[] { url });
        } else if (osName.startsWith("Windows")) {
            Runtime.getRuntime().exec(
                    "rundll32 url.dll,FileProtocolHandler " + url);
        } else { // assume Unix or Linux
            String[] browsers = { "firefox", "opera", "konqueror", "epiphany",
                    "mozilla", "netscape" };
            String browser = null;
            for (int count = 0; count < browsers.length && browser == null; count++)
                if (Runtime.getRuntime()
                        .exec(new String[] { "which", browsers[count] })
                        .waitFor() == 0)
                    browser = browsers[count];
            if (browser == null)
                throw new NoSuchMethodException("Could not find web browser");
            else
                Runtime.getRuntime().exec(new String[] { browser, url });
        }
    }

}

URLEncodeUtils.java

package weibo4j.util;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.BitSet;

/**
 * @author sinaWeibo
 * 
 */
public class URLEncodeUtils {

    static BitSet dontNeedEncoding;

    static {

        /*
         * The list of characters that are not encoded has been determined as
         * follows:
         * 
         * RFC 2396 states: ----- Data characters that are allowed in a URI but
         * do not have a reserved purpose are called unreserved. These include
         * upper and lower case letters, decimal digits, and a limited set of
         * punctuation marks and symbols.
         * 
         * unreserved = alphanum | mark
         * 
         * mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
         * 
         * Unreserved characters can be escaped without changing the semantics
         * of the URI, but this should not be done unless the URI is being used
         * in a context that does not allow the unescaped character to appear.
         * -----
         * 
         * It appears that both Netscape and Internet Explorer escape all
         * special characters from this list with the exception of "-", "_",
         * ".", "*". While it is not clear why they are escaping the other
         * characters, perhaps it is safest to assume that there might be
         * contexts in which the others are unsafe if not escaped. Therefore, we
         * will use the same list. It is also noteworthy that this is consistent
         * with O'Reilly's "HTML: The Definitive Guide" (page 164).
         * 
         * As a last note, Intenet Explorer does not encode the "@" character
         * which is clearly not unreserved according to the RFC. We are being
         * consistent with the RFC in this matter, as is Netscape.
         */

        dontNeedEncoding = new BitSet(256);
        int i;
        for (i = 'a'; i <= 'z'; i++) {
            dontNeedEncoding.set(i);
        }
        for (i = 'A'; i <= 'Z'; i++) {
            dontNeedEncoding.set(i);
        }
        for (i = '0'; i <= '9'; i++) {
            dontNeedEncoding.set(i);
        }
        dontNeedEncoding.set(' '); /*
                                     * encoding a space to a + is done in the
                                     * encode() method
                                     */
        dontNeedEncoding.set('-');
        dontNeedEncoding.set('_');
        dontNeedEncoding.set('.');
        dontNeedEncoding.set('*');

        dontNeedEncoding.set('+');
        dontNeedEncoding.set('%');

    }

    /**
     * 判断段落文本是否被urlencode过
     * 
     * @param str
     * @return
     */
    public static final boolean isURLEncoded(String str) {
        if (str == null || "".equals(str)) {
            return false;
        }
        char[] chars = str.toCharArray();
        boolean containsPercent = false;
        for (char c : chars) {
            if (Character.isWhitespace(c)) {
                return false;
            }
            if (!dontNeedEncoding.get(c)) {
                return false;
            }
            if (c == '%') {
                containsPercent = true;
            }
        }
        if (!containsPercent) {
            return false;
        }
        return true;
    }

    public static final String encodeURL(String str) {
        try {
            return URLEncoder.encode(str, "utf-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }

    public static final String decodeURL(String str) {
        try {
            return URLDecoder.decode(str, "utf-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }

}

WeiboConfig.java

package weibo4j.util;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;

public class WeiboConfig {
    public WeiboConfig() {
    }

    private static Properties props = new Properties();
    static {
        try {
            props.load(Thread.currentThread().getContextClassLoader()
                    .getResourceAsStream("config.properties"));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static String getValue(String key) {
        return props.getProperty(key);
    }

    public static void updateProperties(String key, String value) {
        props.setProperty(key, value);
    }
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值