Skip to content

Commit

Permalink
generator-java: Improve json handling (#56)
Browse files Browse the repository at this point in the history
- Fix java mapping of timestamp
- Replace explicit JsonProperty annotation on every field with Jackson's PropertyNamingStrategy option
  • Loading branch information
sonallux committed Mar 14, 2021
1 parent 9a1de85 commit 9ea96b8
Show file tree
Hide file tree
Showing 58 changed files with 843 additions and 167 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,13 @@ private Map<String, Object> buildPropertyContext(SpotifyWebApiObject.Property pr
var propertyName = property.getName();
if (JavaUtils.RESERVED_WORDS.contains(propertyName)) {
context.put("isReservedKeywordProperty", true);
context.put("jsonName", propertyName);
context.put("fieldName", "_" + propertyName);
} else if (propertyName.contains("_")) {
} else {
// spotify property names are in lower underscore case (e.g album_type)
// but java convention is lower camel case for fields, therefore transform
context.put("jsonName", propertyName);
// JsonProperty annotation is not needed, because the object mapper is configured
// with the correct property naming strategy
context.put("fieldName", LOWER_UNDERSCORE.converterTo(LOWER_CAMEL).convert(propertyName));
} else {
context.put("fieldName", propertyName);
}

var description = property.getDescription();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
import java.util.Map;
import java.util.stream.Collectors;

import static com.google.common.base.CaseFormat.LOWER_CAMEL;
import static com.google.common.base.CaseFormat.LOWER_UNDERSCORE;

public class RequestBodyTemplate extends AbstractTemplate<EndpointRequestBodyObject> {
@Override
String templateName() {
Expand Down Expand Up @@ -49,11 +52,12 @@ Map<String, Object> buildContext(EndpointRequestBodyObject object, Map<String, O

private Map<String, Object> buildPropertyContext(Property property) {
var context = new HashMap<String, Object>();
if (JavaUtils.RESERVED_WORDS.contains(property.getName())) {
context.put("jsonName", property.getName());
context.put("fieldName", "_" + property.getName());
var propertyName = property.getName();
if (JavaUtils.RESERVED_WORDS.contains(propertyName)) {
context.put("isReservedKeywordProperty", true);
context.put("fieldName", "_" + propertyName);
} else {
context.put("fieldName", property.getName());
context.put("fieldName", LOWER_UNDERSCORE.converterTo(LOWER_CAMEL).convert(propertyName));
}

var description = property.getDescription();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public static String shrinkEndpointId(SpotifyWebApiEndpoint endpoint) {
public static String mapToJavaType(String type) {
Matcher matcher;
if ("Timestamp".equals(type)) {
return "java.time.LocalDateTime";
return "java.time.Instant";
} else if ("Object".equals(type)) {
return "java.util.Map<String, Object>";
} else if ("Void".equals(type)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ package {{package}};

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import {{basePackage}}.apis.*;
import de.sonallux.spotify.api.util.JacksonConverterFactory;
import lombok.Getter;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.converter.jackson.JacksonConverterFactory;

@Getter
public class SpotifyWebApi extends BaseSpotifyApi {
Expand Down Expand Up @@ -42,11 +44,13 @@ public class SpotifyWebApi extends BaseSpotifyApi {

private static Retrofit createDefaultRetrofit(OkHttpClient okHttpClient, HttpUrl baseUrl) {
var mapper = new ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE)
.registerModule(new JavaTimeModule());
return new Retrofit.Builder()
.baseUrl(baseUrl)
.client(okHttpClient)
.addConverterFactory(JacksonConverterFactory.create(mapper))
.addConverterFactory(new JacksonConverterFactory(mapper))
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@ public class {{className}}{{#superClass}} extends {{superClass}}{{/superClass}}
{{#nonNull}}
@NonNull
{{/nonNull}}
{{#jsonName}}
@com.fasterxml.jackson.annotation.JsonProperty("{{jsonName}}")
{{/jsonName}}
{{#isReservedKeywordProperty}}
@lombok.experimental.Accessors(prefix = "_")
{{/isReservedKeywordProperty}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,9 @@ public class {{className}} {
{{#required}}
@NonNull
{{/required}}
{{#jsonName}}
@com.fasterxml.jackson.annotation.JsonProperty("{{jsonName}}")
{{#isReservedKeywordProperty}}
@lombok.experimental.Accessors(prefix = "_")
{{/jsonName}}
{{/isReservedKeywordProperty}}
private{{#required}} final{{/required}} {{type}} {{fieldName}};
{{/properties}}
}
11 changes: 8 additions & 3 deletions spotify-web-api-java/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,14 @@
<version>${retrofit.version}</version>
</dependency>
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>converter-jackson</artifactId>
<version>${retrofit.version}</version>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import de.sonallux.spotify.api.apis.*;
import de.sonallux.spotify.api.util.JacksonConverterFactory;
import lombok.Getter;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.converter.jackson.JacksonConverterFactory;

@Getter
public class SpotifyWebApi extends BaseSpotifyApi {
Expand Down Expand Up @@ -64,11 +66,13 @@ public SpotifyWebApi() {

private static Retrofit createDefaultRetrofit(OkHttpClient okHttpClient, HttpUrl baseUrl) {
var mapper = new ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE)
.registerModule(new JavaTimeModule());
return new Retrofit.Builder()
.baseUrl(baseUrl)
.client(okHttpClient)
.addConverterFactory(JacksonConverterFactory.create(mapper))
.addConverterFactory(new JacksonConverterFactory(mapper))
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ public class Album {
/**
* <p>The type of the album: <code>album</code>, <code>single</code>, or <code>compilation</code>.</p>
*/
@com.fasterxml.jackson.annotation.JsonProperty("album_type")
public String albumType;
/**
* <p>The artists of the album. Each artist object includes a link in <code>href</code> to more detailed information about the artist.</p>
Expand All @@ -21,7 +20,6 @@ public class Album {
/**
* <p>The markets in which the album is available: <a href="http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2">ISO 3166-1 alpha-2 country codes</a>. Note that an album is considered available in a market when at least 1 of its tracks is available in that market.</p>
*/
@com.fasterxml.jackson.annotation.JsonProperty("available_markets")
public java.util.List<String> availableMarkets;
/**
* <p>The copyright statements of the album.</p>
Expand All @@ -30,12 +28,10 @@ public class Album {
/**
* <p>Known external IDs for the album.</p>
*/
@com.fasterxml.jackson.annotation.JsonProperty("external_ids")
public ExternalId externalIds;
/**
* <p>Known external URLs for this album.</p>
*/
@com.fasterxml.jackson.annotation.JsonProperty("external_urls")
public ExternalUrl externalUrls;
/**
* <p>A list of the genres used to classify the album. For example: &quot;Prog Rock&quot; , &quot;Post-Grunge&quot;. (If not yet classified, the array is empty.)</p>
Expand Down Expand Up @@ -68,12 +64,10 @@ public class Album {
/**
* <p>The date the album was first released, for example &quot;1981-12-15&quot;. Depending on the precision, it might be shown as &quot;1981&quot; or &quot;1981-12&quot;.</p>
*/
@com.fasterxml.jackson.annotation.JsonProperty("release_date")
public String releaseDate;
/**
* <p>The precision with which release_date value is known: &quot;year&quot; , &quot;month&quot; , or &quot;day&quot;.</p>
*/
@com.fasterxml.jackson.annotation.JsonProperty("release_date_precision")
public String releaseDatePrecision;
/**
* <p>Included in the response when a content restriction is applied. See <a href="https://developer.spotify.com/documentation/web-api/reference/#object-albumrestrictionobject">Restriction Object</a> for more details.</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ public class Artist {
/**
* <p>Known external URLs for this artist.</p>
*/
@com.fasterxml.jackson.annotation.JsonProperty("external_urls")
public ExternalUrl externalUrls;
/**
* <p>Information about the followers of the artist.</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ public class AudioFeatures {
/**
* <p>An HTTP URL to access the full audio analysis of this track. An access token is required to access this data.</p>
*/
@com.fasterxml.jackson.annotation.JsonProperty("analysis_url")
public String analysisUrl;
/**
* <p>Danceability describes how suitable a track is for dancing based on a combination of musical elements including tempo, rhythm stability, beat strength, and overall regularity. A value of 0.0 is least danceable and 1.0 is most danceable.</p>
Expand All @@ -25,7 +24,6 @@ public class AudioFeatures {
/**
* <p>The duration of the track in milliseconds.</p>
*/
@com.fasterxml.jackson.annotation.JsonProperty("duration_ms")
public int durationMs;
/**
* <p>Energy is a measure from 0.0 to 1.0 and represents a perceptual measure of intensity and activity. Typically, energetic tracks feel fast, loud, and noisy. For example, death metal has high energy, while a Bach prelude scores low on the scale. Perceptual features contributing to this attribute include dynamic range, perceived loudness, timbre, onset rate, and general entropy.</p>
Expand Down Expand Up @@ -66,12 +64,10 @@ public class AudioFeatures {
/**
* <p>An estimated overall time signature of a track. The time signature (meter) is a notational convention to specify how many beats are in each bar (or measure).</p>
*/
@com.fasterxml.jackson.annotation.JsonProperty("time_signature")
public int timeSignature;
/**
* <p>A link to the Web API endpoint providing full details of the track.</p>
*/
@com.fasterxml.jackson.annotation.JsonProperty("track_href")
public String trackHref;
/**
* <p>The object type: &quot;audio_features&quot;</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,5 @@
@Setter
@NoArgsConstructor
public class AudioFeaturesArray {
@com.fasterxml.jackson.annotation.JsonProperty("audio_features")
public java.util.List<AudioFeatures> audioFeatures;
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ public class ChangePlaylistDetailsRequest {
/**
* <p>If <code>true</code> the playlist will be public, if <code>false</code> it will be private.</p>
*/
@com.fasterxml.jackson.annotation.JsonProperty("public")
@lombok.experimental.Accessors(prefix = "_")
private boolean _public;
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ public class Context {
/**
* <p>External URLs for this context.</p>
*/
@com.fasterxml.jackson.annotation.JsonProperty("external_urls")
public ExternalUrl externalUrls;
/**
* <p>A link to the Web API endpoint providing full details of the track.</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ public class CreatePlaylistRequest {
/**
* <p>Defaults to <code>true</code> . If <code>true</code> the playlist will be public, if <code>false</code> it will be private. To be able to create private playlists, the user must have granted the <code>playlist-modify-private</code> <a href="https://developer.spotify.com/documentation/general/guides/authorization-guide/#list-of-scopes">scope</a></p>
*/
@com.fasterxml.jackson.annotation.JsonProperty("public")
@lombok.experimental.Accessors(prefix = "_")
private boolean _public;
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,10 @@ public class CurrentlyPlaying {
/**
* <p>The object type of the currently playing item. Can be one of <code>track</code>, <code>episode</code>, <code>ad</code> or <code>unknown</code>.</p>
*/
@com.fasterxml.jackson.annotation.JsonProperty("currently_playing_type")
public String currentlyPlayingType;
/**
* <p>If something is currently playing, return <code>true</code>.</p>
*/
@com.fasterxml.jackson.annotation.JsonProperty("is_playing")
public boolean isPlaying;
/**
* <p>The currently playing track or episode. Can be <code>null</code>.</p>
Expand All @@ -30,7 +28,6 @@ public class CurrentlyPlaying {
/**
* <p>Progress into the currently playing track or episode. Can be <code>null</code>.</p>
*/
@com.fasterxml.jackson.annotation.JsonProperty("progress_ms")
public int progressMs;
/**
* <p>Unix Millisecond Timestamp when data was fetched</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ public class CurrentlyPlayingContext {
/**
* <p>The object type of the currently playing item. Can be one of <code>track</code>, <code>episode</code>, <code>ad</code> or <code>unknown</code>.</p>
*/
@com.fasterxml.jackson.annotation.JsonProperty("currently_playing_type")
public String currentlyPlayingType;
/**
* <p>The device that is currently active.</p>
Expand All @@ -29,7 +28,6 @@ public class CurrentlyPlayingContext {
/**
* <p>If something is currently playing, return <code>true</code>.</p>
*/
@com.fasterxml.jackson.annotation.JsonProperty("is_playing")
public boolean isPlaying;
/**
* <p>The currently playing track or episode. Can be <code>null</code>.</p>
Expand All @@ -38,17 +36,14 @@ public class CurrentlyPlayingContext {
/**
* <p>Progress into the currently playing track or episode. Can be <code>null</code>.</p>
*/
@com.fasterxml.jackson.annotation.JsonProperty("progress_ms")
public int progressMs;
/**
* <p>off, track, context</p>
*/
@com.fasterxml.jackson.annotation.JsonProperty("repeat_state")
public String repeatState;
/**
* <p>If shuffle is on or off.</p>
*/
@com.fasterxml.jackson.annotation.JsonProperty("shuffle_state")
public String shuffleState;
/**
* <p>Unix Millisecond Timestamp when data was fetched.</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,14 @@ public class Device {
/**
* <p>If this device is the currently active device.</p>
*/
@com.fasterxml.jackson.annotation.JsonProperty("is_active")
public boolean isActive;
/**
* <p>If this device is currently in a private session.</p>
*/
@com.fasterxml.jackson.annotation.JsonProperty("is_private_session")
public boolean isPrivateSession;
/**
* <p>Whether controlling this device is restricted. At present if this is &quot;true&quot; then no Web API commands will be accepted by this device.</p>
*/
@com.fasterxml.jackson.annotation.JsonProperty("is_restricted")
public boolean isRestricted;
/**
* <p>The name of the device.</p>
Expand All @@ -39,6 +36,5 @@ public class Device {
/**
* <p>The current volume in percent. This may be null.</p>
*/
@com.fasterxml.jackson.annotation.JsonProperty("volume_percent")
public int volumePercent;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ public class Disallows {
/**
* <p>Interrupting playback. Optional field.</p>
*/
@com.fasterxml.jackson.annotation.JsonProperty("interrupting_playback")
public boolean interruptingPlayback;
/**
* <p>Pausing. Optional field.</p>
Expand All @@ -29,31 +28,25 @@ public class Disallows {
/**
* <p>Skipping to the next context. Optional field.</p>
*/
@com.fasterxml.jackson.annotation.JsonProperty("skipping_next")
public boolean skippingNext;
/**
* <p>Skipping to the previous context. Optional field.</p>
*/
@com.fasterxml.jackson.annotation.JsonProperty("skipping_prev")
public boolean skippingPrev;
/**
* <p>Toggling repeat context flag. Optional field.</p>
*/
@com.fasterxml.jackson.annotation.JsonProperty("toggling_repeat_context")
public boolean togglingRepeatContext;
/**
* <p>Toggling repeat track flag. Optional field.</p>
*/
@com.fasterxml.jackson.annotation.JsonProperty("toggling_repeat_track")
public boolean togglingRepeatTrack;
/**
* <p>Toggling shuffle flag. Optional field.</p>
*/
@com.fasterxml.jackson.annotation.JsonProperty("toggling_shuffle")
public boolean togglingShuffle;
/**
* <p>Transfering playback between devices. Optional field.</p>
*/
@com.fasterxml.jackson.annotation.JsonProperty("transferring_playback")
public boolean transferringPlayback;
}
Loading

0 comments on commit 9ea96b8

Please sign in to comment.