0

I have spent days on this. I have looked at a million different posts from other people having similar issues and tried tons of different things, but I cannot get my json file read in to my program.

It is a school assignment. The demo was for a media library which read in an example music.json file and displayed the tracks in a JTree. Our first assignment was to convert the generic media library to a music specific library, add Track and Album classes, and get search results from last.fm when an album and artist was searched through the app and display the results in the JTree.

I managed to make my Album and Track classes, read in the last.fm json and convert it to an Album Object. I then rewrote that Album object to a new album.json file. I have since started working on reading that json file back in to the MusicLibrary class so that it can display the results in the JTree. That is where I am running into trouble. I have to do some converting because the given music.json is meant for organizing by tracks (before there was an Album class), and now I need it to work off of the new Album class (which contains a Vector of Track objects).

I cannot use any tools that need maven or downloaded jar's to work (so no GSON, etc.). I have to use org.json methods only. The instructor's original code read the music.json into a HashTable. I have tried reading it into that, into a Vector, and into a HashMap. Nothing works. I keep getting the error's:

Exception reading music library album.json: JSONObject["channel"] is not a JSONObject. or Exception reading music library album.json: JSONObject["album"] is not a JSONObject.

or no error but then when I try to print the table/map/vector, it is always empty. The first error is when I don't use the JSONTokener and use the commented-out line below it. I have no idea where it is coming up with "channel". That is nowhere in my code. Anyway, I am posting my relevant code below. If you see tons of commented-out lines, those are all different things I have tried and/or some of the instructor's original code (such as the HashTable lib).

album.json (which I put into a formatter and validator for better display)

{
  "album": "Believe",
  "albumTracks": [
    {
      "trackInfo": "Track Name: Believe\nArtist: Cher\nRank: 1\nDuration: 241\n\n",
      "trackArtist": "Cher",
      "trackRank": "1",
      "trackDuration": "241",
      "trackTitle": "Believe"
    },
    {
      "trackInfo": "Track Name: The Power\nArtist: Cher\nRank: 2\nDuration: 236\n\n",
      "trackArtist": "Cher",
      "trackRank": "2",
      "trackDuration": "236",
      "trackTitle": "The Power"
    },
    {
      "trackInfo": "Track Name: Runaway\nArtist: Cher\nRank: 3\nDuration: 286\n\n",
      "trackArtist": "Cher",
      "trackRank": "3",
      "trackDuration": "286",
      "trackTitle": "Runaway"
    },
    {
      "trackInfo": "Track Name: All or Nothing\nArtist: Cher\nRank: 4\nDuration: 237\n\n",
      "trackArtist": "Cher",
      "trackRank": "4",
      "trackDuration": "237",
      "trackTitle": "All or Nothing"
    },
    {
      "trackInfo": "Track Name: Strong Enough\nArtist: Cher\nRank: 5\nDuration: 223\n\n",
      "trackArtist": "Cher",
      "trackRank": "5",
      "trackDuration": "223",
      "trackTitle": "Strong Enough"
    },
    {
      "trackInfo": "Track Name: Dov'e L'amore\nArtist: Cher\nRank: 6\nDuration: 258\n\n",
      "trackArtist": "Cher",
      "trackRank": "6",
      "trackDuration": "258",
      "trackTitle": "Dov'e L'amore"
    },
    {
      "trackInfo": "Track Name: Takin' Back My Heart\nArtist: Cher\nRank: 7\nDuration: 272\n\n",
      "trackArtist": "Cher",
      "trackRank": "7",
      "trackDuration": "272",
      "trackTitle": "Takin' Back My Heart"
    },
    {
      "trackInfo": "Track Name: Taxi Taxi\nArtist: Cher\nRank: 8\nDuration: 304\n\n",
      "trackArtist": "Cher",
      "trackRank": "8",
      "trackDuration": "304",
      "trackTitle": "Taxi Taxi"
    },
    {
      "trackInfo": "Track Name: Love Is the Groove\nArtist: Cher\nRank: 9\nDuration: 271\n\n",
      "trackArtist": "Cher",
      "trackRank": "9",
      "trackDuration": "271",
      "trackTitle": "Love Is the Groove"
    },
    {
      "trackInfo": "Track Name: We All Sleep Alone\nArtist: Cher\nRank: 10\nDuration: 233\n\n",
      "trackArtist": "Cher",
      "trackRank": "10",
      "trackDuration": "233",
      "trackTitle": "We All Sleep Alone"
    }
  ],
  "albumArtist": "Cher",
  "albumSummary": "Believe is the twenty-third studio album by American  singer-actress Cher, released on November 10, 1998 by Warner Bros. Records. The RIAA certified it Quadruple Platinum on December 23, 1999, recognizing four million shipments in the United States; Worldwide, the album has sold more than 20 million copies, making it the biggest-selling album of her career. In 1999 the album received three Grammy Awards nominations including \"Record of the Year\", \"Best Pop Album\" and winning \"Best Dance Recording\" for the single \"Believe\". <a href=\"http://www.last.fm/music/Cher/Believe\">Read more on Last.fm</a>.",
  "albumImage": "https://lastfm.freetls.fastly.net/i/u/174s/b0c2311a9af7f0edbc8b99450944ca1b.png"
}

My Album.java class so you can see how I write the Album object to Json in case that is the issue.

    /**
     * Converts the Album object along with its associated Track objects to a JSONObject toString
     * 
     * @return Returns the Album/Track objects as a JSONObject toString
     */
    public String toJString() {
        String jString = "{}";
        try {
            jString = this.albumToJObject().toString(0);
        } catch (Exception ex) {
            System.out.println("Exception in Album toJString: " + ex.getMessage());
        }
        return jString;
    }

    /**
     * Converts the Track object to a JSONObject.
     * 
     * @return Returns the Track object as a JSONObject.
     */
    public JSONObject albumToJObject() {
        JSONObject jObject = new JSONObject();
        try {
            jObject.put("album", albumName);
            jObject.put("albumArtist", albumArtist);
            jObject.put("albumImage", albumImage);
            jObject.put("albumSummary", albumSummary);
            jObject.put("albumTracks", (Object)albumTracks);

            // System.out.println("Full Album JSONObject: " + jObject.toString());

        } catch (Exception ex) {
            System.out.println("Exception in Album toJObject: " + ex.getMessage());
        }
        return jObject;
    }

    public void writeAlbumToJson() {
        try {
            Writer output = null;
            File file = new File("album.json");
            output = new BufferedWriter(new FileWriter(file));
            output.write(this.albumToJObject().toString());
            output.close();
        } catch (Exception ex) {
            ex.printStackTrace();
            System.out.println("Exception in writeAlbumToJson: " + ex.getMessage());
        }
    }

Here is the MusicLibrary class declaration and constructor, cleaned up for clarity of what my current code is:

public class MusicLibrary extends Object implements Serializable {

    private Map<String, Album> musicLib;
    private static final String mFileName = "album.json";

    public MusicLibrary() {
        this.musicLib = new HashMap<String, Album>();
        try {
            InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(this.mFileName);
            if (inputStream == null) {
                inputStream = new FileInputStream(new File(this.mFileName));
            }
            JSONObject music = new JSONObject(new JSONTokener(inputStream));
            Iterator<String> iter = music.keys();

            while(iter.hasNext()) {
                String key = iter.next();
                JSONObject jAlbumObj = music.optJSONObject(key);
                if (music.get(key) instanceof JSONObject) {
                    Album album = new Album(jAlbumObj);
                    musicLib.put(key, album);      
                }
            }

            System.out.println("DEBUG: musicLib HashMap contents: " + musicLib.toString());
        } catch (Exception ex) {
            ex.printStackTrace();
            System.out.println("Exception reading music library " + mFileName + ": " + ex.getMessage());
        }
    }
Krista
  • 19
  • 5
  • 1
    To start with, read the Javadocs for the classes you're using; `Vector` and `Hashtable` have been obsolete for 20 years (use `List` and `Map` instead). You also need to trim down your code to find the smallest version that will cause the error; there's too much here for us to sort through. In doing that, you are likely to find the specific mismatch. – chrylis -cautiouslyoptimistic- Feb 09 '20 at 00:18
  • I know Vector and Hashtable are obsolete, but for some reason, the instructor is using both. I did try both Vector and ArrayList in my Album class for the Tracks, and finally got that to work with Vector. In the MusicLibrary class, I have switched over to Map (the instructor used HT and I left his declaration in there, but am not using it anywhere). The biggest problem is in the MusicLibrary constructor, getting the json file into the Map. I added the extra commented out code to show what other things I have tried. – Krista Feb 09 '20 at 02:08
  • I just posted the cleaned up MusicLibrary.java class – Krista Feb 09 '20 at 02:16
  • Does anyone have any idea for this? My best guess is actually that something is wrong with the Json file itself. I feel that my read Json code is correct as it matches this reply https://stackoverflow.com/a/4149555/9576364 and many others (aside from the fact that my map is a rather than a . – Krista Feb 09 '20 at 19:55

1 Answers1

0

From your explanation, I understand that the MusicLibrary should read the album.json file and convert it into the map Map<String, Album> musicLib; , where the key is the name of the album.

You do not provide the whole Album and Track classes, but I will assume they have constructors that take JSONObject arguments.

Your error is where you are trying to iterate over the JSONObject. The iter.next() will always return just an Object, not a JSONObject like you want. Also, considering that the album.json you provided only has one album, there is no point in iterating at all (unless the album.json is supposed to have multiple albums).

Also, I suppose the json structure (key names) is known so that you can use the names to extract data. See the code below:

public class MusicLibrary{

    private Map<String, Album> musicLib;
    private static final String mFileName = "album.json";

    public MusicLibrary() {
        this.musicLib = new HashMap<>();
        try {
            InputStream inputStream = getClass().getClassLoader().getResourceAsStream(this.mFileName);
            if (inputStream == null) {
                inputStream = new FileInputStream(new File(this.mFileName));
            }

            JSONObject jAlbum = new JSONObject(new JSONTokener(inputStream));
            Album album = new Album(jAlbum);
            musicLib.put(album.getAlbumName(), album);

            System.out.println("DEBUG: musicLib HashMap contents: " + musicLib.toString());
        } catch (Exception ex) {
            ex.printStackTrace();
            System.out.println("Exception reading music library " + mFileName + ": " + ex.getMessage());
        }
    }


}

public class Album {

    private String albumName;
    private String albumArtist;
    private String albumImage;
    private String albumSummary;
    private List<Track> albumTracks = new LinkedList<>();

    public Album(JSONObject obj) {
        albumName = obj.getString("album");
        albumArtist = obj.getString("albumArtist");
        albumImage = obj.getString("albumImage");
        albumSummary = obj.getString("albumSummary");
        JSONArray tracks = obj.getJSONArray("albumTracks");

        for (int i = 0; i < tracks.length(); i++) {
            albumTracks.add(new Track(tracks.getJSONObject(i)));
        }
    }

    public String getAlbumName() {
        return albumName;
    }


    @Override
    public String toString() {
        return "Album{" +
                "albumName='" + albumName + '\'' +
                ", albumArtist='" + albumArtist + '\'' +
                ", albumImage='" + albumImage + '\'' +
                ", albumSummary='" + albumSummary + '\'' +
                ", albumTracks=" + albumTracks +
                '}';
    }
}

public class Track {
    private String trackInfo;
    private String trackArtist;
    private String trackRank;
    private String trackDuration;
    private String trackTitle;

    public Track(JSONObject obj) {
        trackInfo = obj.getString("trackInfo");
        trackArtist = obj.getString("trackArtist");
        trackRank = obj.getString("trackRank");
        trackDuration = obj.getString("trackDuration");
        trackTitle = obj.getString("trackTitle");
    }
    @Override
    public String toString() {
        return "Track{" +
                "trackInfo='" + trackInfo + '\'' +
                ", trackArtist='" + trackArtist + '\'' +
                ", trackRank='" + trackRank + '\'' +
                ", trackDuration='" + trackDuration + '\'' +
                ", trackTitle='" + trackTitle + '\'' +
                '}';
    }
}

Finally, consider removing logic and file reading from the MusicLibrary constructor, do not extend Object explicitly and do not implement Serializable unless you really know what you are doing.

Backflip
  • 232
  • 2
  • 9
  • Thank you for your detailed reply. My original goal was to have it so that eventually the format of the album.json would replace the format of the music.json and that it would read in multiple albums to populate the library (and persist). Also, I do have to extend Object and implement Serializable as per the instructor's instructions. Anyway, I was told that I was making it too complicated, and that my only goal was to display the new search results in the JTree, so I went about it in a way that does not take in the new .json file, but instead adds the Album object to the Map directly/ – Krista Feb 10 '20 at 18:56
  • I will try your suggestions though once I get this round-about way working because this new way doesn't persist my data. – Krista Feb 10 '20 at 18:58