package com.github.jreddit.parser.single; import static com.github.jreddit.parser.util.JsonUtils.safeJsonToString; import java.util.ArrayList; import java.util.List; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException; import com.github.jreddit.parser.entity.Comment; import com.github.jreddit.parser.entity.Kind; import com.github.jreddit.parser.entity.More; import com.github.jreddit.parser.entity.Submission; import com.github.jreddit.parser.entity.imaginary.CommentTreeElement; import com.github.jreddit.parser.entity.imaginary.FullSubmission; import com.github.jreddit.parser.exception.RedditParseException; import com.github.jreddit.parser.util.JsonUtils; public class FullSubmissionParser { protected static final JSONParser JSON_PARSER = new JSONParser(); /** * Parse JSON received from reddit into a full submission. * A full submissions means it has both (a) the submission, and (b) the comment tree. * * @param jsonText JSON Text * @return Full submission * * @throws ParseException */ public FullSubmission parse(String jsonText) throws RedditParseException { try { // Parse JSON text Object response = JSON_PARSER.parse(jsonText); // Validate response validate(response); // Create submission (casting with JSON is horrible) JSONObject main = (JSONObject) ((JSONArray) response).get(0); Submission submission = new Submission((JSONObject) ((JSONObject) ((JSONArray)((JSONObject) main.get("data")).get("children")).get(0)).get("data")); // Create comment tree JSONObject mainTree = (JSONObject) ((JSONArray) response).get(1); List commentTree = parseRecursive(mainTree); // Return the set of submission and its comment tree return new FullSubmission(submission, commentTree); } catch (ParseException pe) { throw new RedditParseException(pe); } } /** * Parse a JSON object consisting of comments and add them * to the already existing list of comments. This does NOT create * a new comment list. * * @param comments List of comments * @param object JSON Object */ protected List parseRecursive(JSONObject main) throws RedditParseException { List commentTree = new ArrayList(); // Iterate over the comment tree results JSONArray array = (JSONArray) ((JSONObject) main.get("data")).get("children"); for (Object element : array) { // Get the element JSONObject data = (JSONObject) element; // Make sure it is of the correct kind String kind = safeJsonToString(data.get("kind")); // If it is a comment if (kind != null && kind.equals(Kind.COMMENT.value())) { // Create comment Comment comment = new Comment( (JSONObject) data.get("data") ); // Retrieve replies Object replies = ((JSONObject) data.get("data")).get("replies"); // If it is an JSON object if (replies instanceof JSONObject) { comment.setReplies(parseRecursive( (JSONObject) replies )); // If there are no replies, end with an empty one } else { comment.setReplies(new ArrayList()); } // Add comment to the tree commentTree.add(comment); } // If it is a more if (kind != null && kind.equals(Kind.MORE.value())) { // Add to comment tree commentTree.add(new More((JSONObject) data.get("data"))); } } return commentTree; } /** * Validate that it is in fact a full submission. * * @param response Object from the JSON parser * * @throws RedditRequestException If the JSON is in incorrect format */ public void validate(Object response) throws RedditParseException { // Check for null if (response == null) { throw new RedditParseException(); } // Check it is a JSON response if (response instanceof JSONObject) { // Cast to JSON object JSONObject jsonResponse = (JSONObject) response; // Check for error if (jsonResponse.get("error") != null) { throw new RedditParseException(JsonUtils.safeJsonToInteger(jsonResponse.get("error"))); } else { throw new RedditParseException("invalid json format, started with object (should start with array)"); } } // It must start with an array if (!(response instanceof JSONArray)) { throw new RedditParseException("invalid json format, did not start with array"); } } }