In my Java
program, I am trying to parse data that I get from Strava.com's API. One of the JSON
payloads, I receive from there looks as follows:
[
{"type": "altitude","data": [519.1,519.3,519.3,519.4,519.5],"series_type": "distance","original_size": 5,"resolution": "high"},
{"type": "latlng","data": [[46.01234,6.01234],[46.11234,6.11234],[46.21234,6.21234],[46.31234,6.31234],[46.41234,6.41234]],"series_type": "distance","original_size": 5,"resolution": "high"},
{"type": "velocity_smooth","data": [0.0,0.0,0.0,5.5,5.2],"series_type": "distance","original_size": 5,"resolution": "high"},
{"type": "distance","data": [0.0,8.6,11.8,16.6,20.8],"series_type": "distance","original_size": 5,"resolution": "high"},
{"type": "time","data": [0,1,2,3,4],"series_type": "distance","original_size": 5,"resolution": "high"}
]
Basically, four of these entries (altitude, velocity_smooth, distance and time) have the same structure (their data
field is an array of doubles (or ints that can be parsed as doubles)), but the second entry (latlng) has a slighlty different structure for the data
field (it is a an array of arrays of double).
I am familiar with the Jackson
library to convert between JSON
and POJO
s if all the content is named, but do not see how I can model the above data structure to deserialise it.
Let's say that instead of the data above, it looked as follows:
{
"altitude": {"data": [519.1,519.3,519.3,519.4,519.5],"series_type": "distance","original_size": 5,"resolution": "high"},
"latlng": {"data": [[46.01234,6.01234],[46.11234,6.11234],[46.21234,6.21234],[46.31234,6.31234],[46.41234,6.41234]],"series_type": "distance","original_size": 5,"resolution": "high"},
"velocity_smooth": {"data": [0.0,0.0,0.0,5.5,5.2],"series_type": "distance","original_size": 5,"resolution": "high"},
"distance": {"data": [0.0,8.6,11.8,16.6,20.8],"series_type": "distance","original_size": 5,"resolution": "high"},
"time": {"data": [0,1,2,3,4],"series_type": "distance","original_size": 5,"resolution": "high"}
}
Then I could define the following three classes
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Value;
import java.util.List;
@Getter
@NoArgsConstructor
public class Holder {
DoubleData altitude;
CoordinateData latlng;
@JsonProperty("velocity_smooth") DoubleData velocitySmooth;
DoubleData distance;
DoubleData time;
}
@Getter
@NoArgsConstructor
public class DoubleData {
List<Double> data;
@JsonProperty("series_type") String seriesType;
@JsonProperty("original_size") Integer originalSize;
String resolution;
}
@Getter
@NoArgsConstructor
public class CoordinateData {
List<List<Double>> data;
@JsonProperty("series_type") String seriesType;
@JsonProperty("original_size") Integer originalSize;
String resolution;
}
And then use
objectMapper.readValue(jsonString, Holder.class);
to read in that object. However, as the data received from Strava is an array instead of an object, I am failing. I have read Baeldung's article on how to unmarshal to collections/arrays but that assumes that all classes in the array/collection are the same.
I though about defining an interface which would be extended by the two classes that could be found in the array and then use that mechanism:
public interface Data {
}
@Getter
@NoArgsConstructor
public class DoubleData implements Data {
String type;
List<Double> data;
@JsonProperty("series_type") String seriesType;
@JsonProperty("original_size") Integer originalSize;
String resolution;
}
@Getter
@NoArgsConstructor
public class CoordinateData implements Data {
String type;
List<List<Double>> data;
@JsonProperty("series_type") String seriesType;
@JsonProperty("original_size") Integer originalSize;
String resolution;
}
Data[] array = objectMapper.readValue(jsonString, Data[].class);
But that doesn't work, as I would need to find some way to let it find out when to use a DoubleData
class and when to use a CoordinateData
class.
I am sure, I am not the first person trying to use Strava data in Java
. Can this be done?