Java: Deserialise JSON Array to Map<Integer, Object> according to JSON property id value

Viewed 786

First: I am aware of the fact, that there are a few topics about deserialization of json arrays, but i still could not figure out, how to store/deserialize a JSON-Array which looks like the following using Jackson into a Map<Integer, Song>, so i can access the Map by the ID integer property from the JSON-file. e.g. songStore.get(2) , where the "2" is the map key and matches the Json entry with id: 2. I have tried different approaches, but i am stuck at the error message:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize >instance of java.util.LinkedHashMap out of START_ARRAY token at [Source: (BufferedInputStream); line: 1, column: 1]

If I write it to List<Song> instead, it works, but that is not, what i need.

[
    {
        "id": 1,
        "title": "Title 1",
        "artist": "Artist 1",
        "released": 2012
    },
    {
        "id": 2,
        "title": "Title 2",
        "artist": "Artist 2",
        "album": "Album 2",
        "released": 2014
    },
    {
        "id": 3,
        "title": "Title 3",
        "artist": "Artist 3",
        "album": "Album 3",
        "released": 2016
    },
    {...}
]

My POJO looks like this:

public class Song {

@JsonProperty("id")
private Integer id;

@JsonProperty("title")
private String title;

@JsonProperty("artist")
private String artist;

@JsonProperty("album")
private String album;

@JsonProperty("released")
private Integer released;

public Song () {    }

public Song (Integer id, String title, String artist, String album, Integer released) {
    this.id = id;
    this.title = title;
    this.artist = artist;
    this.album = album;
    this.released = released;
}

public Integer getId() {
    return id;
}

void setId(Integer id) {
    this.id = id;
}

public String getTitle() {
    return title;
}

public String getArtist() {
    return artist;
}

public String getAlbum() {
    return album;
}

public Integer getReleased() {
    return released;
}

}

This is my approach, but i cannot get it to work:

// Reads a list of songs from a JSON-file into Map<Integer, Song>
@SuppressWarnings("unchecked")
static Map<Integer, Song> readJSONToSongsMap (String filename) throws FileNotFoundException, IOException {
    ObjectMapper objectMapper = new ObjectMapper();
    try (InputStream is = new BufferedInputStream(new FileInputStream(filename))) {
        return (Map<Integer, Song>) objectMapper.readValue(is, new TypeReference<Map<Integer, Song>>(){});
    }
}

EDIT: I found a workaround by creating a List with:

@SuppressWarnings("unchecked")
static List<Song> readJSONToSongs (String filename) throws FileNotFoundException, IOException {
    ObjectMapper objectMapper = new ObjectMapper();
    try (InputStream is = new BufferedInputStream(new FileInputStream(filename))) {
        return (List<Song>) objectMapper.readValue(is,  new TypeReference<List<Song>>(){});
    }
}

and then just convert the List to a Hashmap by:

private Map<Integer, Song> songStore = new HashMap<Integer, Song>();
List<Song> readSongs = readJSONToSongs("songs.json");

//convert from list to hashmap with key=getId and value=Song.class object
for(Song i : readSongs) songStore.put(i.getId(),i);

But this approach does not satisfy me.

Any help is much appreciated.

Regards.

1 Answers
Related