Skip to content

Commit

Permalink
Merge pull request apple#58 from alexanderjordanbaker/JacksonFromGSON
Browse files Browse the repository at this point in the history
Switch GSON to Jackson to allow unknownFields to be parsed
  • Loading branch information
alexanderjordanbaker authored Dec 8, 2023
2 parents 0c38080 + ed5fb01 commit bd7985f
Show file tree
Hide file tree
Showing 62 changed files with 1,015 additions and 855 deletions.
7 changes: 2 additions & 5 deletions NOTICE.txt
Original file line number Diff line number Diff line change
Expand Up @@ -212,9 +212,7 @@ okhttp contirbutors (okhttp)

_____________________

Google Inc. (gson)

Google Gson
jackson-databind contributors (jackson-databind)

Apache License
Version 2.0, January 2004
Expand Down Expand Up @@ -404,7 +402,7 @@ Google Gson
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright 2008-2011 Google Inc.
Copyright [yyyy] [name of copyright owner]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand All @@ -417,7 +415,6 @@ Google Gson
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

_____________________

Auth0, Inc. (java-jwt)
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ targetCompatibility = JavaVersion.VERSION_11

dependencies {
implementation 'com.squareup.okhttp3:okhttp:4.11.0'
implementation 'com.google.code.gson:gson:2.10.1'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.16.0'
implementation 'com.auth0:java-jwt:4.4.0'
implementation 'org.bouncycastle:bcprov-jdk15on:1.70'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@
import com.apple.itunes.storekit.model.StatusResponse;
import com.apple.itunes.storekit.model.TransactionHistoryRequest;
import com.apple.itunes.storekit.model.TransactionInfoResponse;
import com.google.gson.Gson;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import okhttp3.Call;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
Expand All @@ -47,7 +50,7 @@ public class AppStoreServerAPIClient {
private final OkHttpClient httpClient;
private final BearerTokenAuthenticator bearerTokenAuthenticator;
private final HttpUrl urlBase;
private final Gson gson;
private final ObjectMapper objectMapper;

/**
* Create an App Store Server API client
Expand All @@ -62,7 +65,13 @@ public AppStoreServerAPIClient(String signingKey, String keyId, String issuerId,
OkHttpClient.Builder builder = new OkHttpClient.Builder();
this.httpClient = builder.build();
this.urlBase = HttpUrl.parse(environment.equals(Environment.SANDBOX) ? SANDBOX_URL : PRODUCTION_URL);
this.gson = new Gson();
this.objectMapper = new ObjectMapper();
objectMapper.setVisibility(objectMapper.getSerializationConfig().getDefaultVisibilityChecker()
.withFieldVisibility(JsonAutoDetect.Visibility.ANY)
.withGetterVisibility(JsonAutoDetect.Visibility.NONE)
.withIsGetterVisibility(JsonAutoDetect.Visibility.NONE)
.withSetterVisibility(JsonAutoDetect.Visibility.NONE)
.withCreatorVisibility(JsonAutoDetect.Visibility.NONE));
}

private Response makeRequest(String path, String method, Map<String, List<String>> queryParameters, Object body) throws IOException {
Expand All @@ -78,7 +87,7 @@ private Response makeRequest(String path, String method, Map<String, List<String
}
requestBuilder.url(urlBuilder.build());
if (body != null) {
RequestBody requestBody = RequestBody.create(gson.toJson(body), JSON);
RequestBody requestBody = RequestBody.create(objectMapper.writeValueAsString(body), JSON);
requestBuilder.method(method, requestBody);
} else if (method.equals("POST")){
requestBuilder.method(method, RequestBody.create("", null));
Expand All @@ -104,13 +113,19 @@ protected <T> T makeHttpCall(String path, String method, Map<String, List<String
if (responseBody == null) {
throw new RuntimeException("Response code was 2xx but no body returned");
}
return gson.fromJson(responseBody.charStream(), clazz);
try {
return objectMapper.readValue(responseBody.charStream(), clazz);
} catch (JsonProcessingException suppressed) {
APIException e = new APIException(r.code());
e.addSuppressed(suppressed);
throw e;
}
} else {
// Best effort to decode the body
try {
ResponseBody responseBody = r.body();
if (responseBody != null) {
ErrorPayload errorPayload = gson.fromJson(responseBody.charStream(), ErrorPayload.class);
ErrorPayload errorPayload = objectMapper.readValue(responseBody.charStream(), ErrorPayload.class);
throw new APIException(r.code(), errorPayload.getErrorCode());
}
} catch (APIException e) {
Expand Down
24 changes: 3 additions & 21 deletions src/main/java/com/apple/itunes/storekit/model/AccountTenure.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,13 @@

package com.apple.itunes.storekit.model;

import com.google.gson.TypeAdapter;
import com.google.gson.annotations.JsonAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;

import java.io.IOException;
import com.fasterxml.jackson.annotation.JsonValue;

/**
* The age of the customer’s account.
*
* @see <a href="https://developer.apple.com/documentation/appstoreserverapi/accounttenure">accountTenure</a>
*/
@JsonAdapter(AccountTenure.Adapter.class)
public enum AccountTenure {

UNDECLARED(0),
Expand All @@ -38,24 +32,12 @@ public static AccountTenure fromValue(Integer value) {
return b;
}
}
throw new IllegalArgumentException("Unexpected value '" + value + "'");
return null;
}

@JsonValue
public Integer getValue() {
return value;
}

public static class Adapter extends TypeAdapter<AccountTenure> {
@Override
public void write(final JsonWriter jsonWriter, final AccountTenure enumeration) throws IOException {
jsonWriter.value(enumeration.getValue());
}

@Override
public AccountTenure read(final JsonReader jsonReader) throws IOException {
Integer value = jsonReader.nextInt();
return AccountTenure.fromValue(value);
}
}
}

64 changes: 44 additions & 20 deletions src/main/java/com/apple/itunes/storekit/model/AppTransaction.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.apple.itunes.storekit.model;

import com.google.gson.annotations.JsonAdapter;
import com.google.gson.annotations.SerializedName;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;

import java.util.Map;
import java.util.Objects;
import java.util.UUID;

Expand All @@ -26,31 +28,33 @@ public class AppTransaction implements DecodedSignedData {
private static final String SERIALIZED_NAME_DEVICE_VERIFICATION_NONCE = "deviceVerificationNonce";
private static final String SERIALIZED_NAME_PREORDER_DATE = "preorderDate";

@SerializedName(SERIALIZED_NAME_RECEIPT_TYPE)
@JsonProperty(SERIALIZED_NAME_RECEIPT_TYPE)
private String receiptType;
@SerializedName(SERIALIZED_NAME_APP_APPLE_ID)
@JsonProperty(SERIALIZED_NAME_APP_APPLE_ID)
private Long appAppleId;
@SerializedName(SERIALIZED_NAME_BUNDLE_ID)
@JsonProperty(SERIALIZED_NAME_BUNDLE_ID)
private String bundleId;
@SerializedName(SERIALIZED_NAME_APPLICATION_VERSION)
@JsonProperty(SERIALIZED_NAME_APPLICATION_VERSION)
private String applicationVersion;
@SerializedName(SERIALIZED_NAME_VERSION_EXTERNAL_IDENTIFIER)
@JsonProperty(SERIALIZED_NAME_VERSION_EXTERNAL_IDENTIFIER)
private Long versionExternalIdentifier;
@SerializedName(SERIALIZED_NAME_RECEIPT_CREATION_DATE)
@JsonAdapter(XcodeCompatibleTimestampDeserializer.class)
@JsonProperty(SERIALIZED_NAME_RECEIPT_CREATION_DATE)
@JsonDeserialize(using = XcodeCompatibleTimestampDeserializer.class)
private Long receiptCreationDate;
@SerializedName(SERIALIZED_NAME_ORIGINAL_PURCHASE_DATE)
@JsonAdapter(XcodeCompatibleTimestampDeserializer.class)
@JsonProperty(SERIALIZED_NAME_ORIGINAL_PURCHASE_DATE)
@JsonDeserialize(using = XcodeCompatibleTimestampDeserializer.class)
private Long originalPurchaseDate;
@SerializedName(SERIALIZED_NAME_ORIGINAL_APPLICATION_VERSION)
@JsonProperty(SERIALIZED_NAME_ORIGINAL_APPLICATION_VERSION)
private String originalApplicationVersion;
@SerializedName(SERIALIZED_NAME_DEVICE_VERIFICATION)
@JsonProperty(SERIALIZED_NAME_DEVICE_VERIFICATION)
private String deviceVerification;
@SerializedName(SERIALIZED_NAME_DEVICE_VERIFICATION_NONCE)
@JsonProperty(SERIALIZED_NAME_DEVICE_VERIFICATION_NONCE)
private UUID deviceVerificationNonce;
@SerializedName(SERIALIZED_NAME_PREORDER_DATE)
@JsonAdapter(XcodeCompatibleTimestampDeserializer.class)
@JsonProperty(SERIALIZED_NAME_PREORDER_DATE)
@JsonDeserialize(using = XcodeCompatibleTimestampDeserializer.class)
private Long preorderDate;
@JsonAnySetter
private Map<String, Object> unknownFields;

/**
The server environment that signs the app transaction.
Expand Down Expand Up @@ -140,7 +144,7 @@ public AppTransaction applicationVersion(String applicationVersion) {
@see <a href="https://developer.apple.com/documentation/storekit/apptransaction/3954438-appversionid">appVersionID</a>
*/
public Long versionExternalIdentifier() {
public Long getVersionExternalIdentifier() {
return this.versionExternalIdentifier;
}

Expand Down Expand Up @@ -176,7 +180,7 @@ public AppTransaction receiptCreationDate(Long receiptCreationDate) {
@see <a href="https://developer.apple.com/documentation/storekit/apptransaction/3954448-originalpurchasedate">originalPurchaseDate</a>
*/
public Long originalPurchaseDate() {
public Long getOriginalPurchaseDate() {
return this.originalPurchaseDate;
}

Expand Down Expand Up @@ -263,6 +267,24 @@ public AppTransaction preorderDate(Long preorderDate) {
return this;
}

/**
Fields that are not recognized for this object
@return A map of JSON keys to objects
*/
public Map<String, Object> getUnknownFields() {
return unknownFields;
}

public void setUnknownFields(Map<String, Object> unknownFields) {
this.unknownFields = unknownFields;
}

public AppTransaction unknownFields(Map<String, Object> unknownFields) {
this.unknownFields = unknownFields;
return this;
}

public Long getSignedDate() {
return getReceiptCreationDate();
}
Expand All @@ -272,12 +294,12 @@ public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AppTransaction that = (AppTransaction) o;
return Objects.equals(receiptType, that.receiptType) && Objects.equals(appAppleId, that.appAppleId) && Objects.equals(bundleId, that.bundleId) && Objects.equals(applicationVersion, that.applicationVersion) && Objects.equals(versionExternalIdentifier, that.versionExternalIdentifier) && Objects.equals(originalPurchaseDate, that.originalPurchaseDate) && Objects.equals(originalApplicationVersion, that.originalApplicationVersion) && Objects.equals(deviceVerification, that.deviceVerification) && Objects.equals(deviceVerificationNonce, that.deviceVerificationNonce) && Objects.equals(preorderDate, that.preorderDate);
return Objects.equals(receiptType, that.receiptType) && Objects.equals(appAppleId, that.appAppleId) && Objects.equals(bundleId, that.bundleId) && Objects.equals(applicationVersion, that.applicationVersion) && Objects.equals(versionExternalIdentifier, that.versionExternalIdentifier) && Objects.equals(originalPurchaseDate, that.originalPurchaseDate) && Objects.equals(originalApplicationVersion, that.originalApplicationVersion) && Objects.equals(deviceVerification, that.deviceVerification) && Objects.equals(deviceVerificationNonce, that.deviceVerificationNonce) && Objects.equals(preorderDate, that.preorderDate) && Objects.equals(unknownFields, that.unknownFields);
}

@Override
public int hashCode() {
return Objects.hash(receiptType, appAppleId, bundleId, applicationVersion, versionExternalIdentifier, originalPurchaseDate, originalApplicationVersion, deviceVerification, deviceVerificationNonce, preorderDate);
return Objects.hash(receiptType, appAppleId, bundleId, applicationVersion, versionExternalIdentifier, originalPurchaseDate, originalApplicationVersion, deviceVerification, deviceVerificationNonce, preorderDate, unknownFields);
}

@Override
Expand All @@ -288,11 +310,13 @@ public String toString() {
", bundleId='" + bundleId + '\'' +
", applicationVersion='" + applicationVersion + '\'' +
", versionExternalIdentifier=" + versionExternalIdentifier +
", receiptCreationDate=" + receiptCreationDate +
", originalPurchaseDate=" + originalPurchaseDate +
", originalApplicationVersion='" + originalApplicationVersion + '\'' +
", deviceVerification='" + deviceVerification + '\'' +
", deviceVerificationNonce=" + deviceVerificationNonce +
", preorderDate=" + preorderDate +
", unknownFields=" + unknownFields +
'}';
}
}
Expand Down
24 changes: 3 additions & 21 deletions src/main/java/com/apple/itunes/storekit/model/AutoRenewStatus.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,13 @@

package com.apple.itunes.storekit.model;

import com.google.gson.TypeAdapter;
import com.google.gson.annotations.JsonAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;

import java.io.IOException;
import com.fasterxml.jackson.annotation.JsonValue;

/**
* The renewal status for an auto-renewable subscription.
*
* @see <a href="https://developer.apple.com/documentation/appstoreserverapi/autorenewstatus">autoRenewStatus</a>
*/
@JsonAdapter(AutoRenewStatus.Adapter.class)
public enum AutoRenewStatus {

OFF(0),
Expand All @@ -32,9 +26,10 @@ public static AutoRenewStatus fromValue(Integer value) {
return b;
}
}
throw new IllegalArgumentException("Unexpected value '" + value + "'");
return null;
}

@JsonValue
public Integer getValue() {
return value;
}
Expand All @@ -43,18 +38,5 @@ public Integer getValue() {
public String toString() {
return String.valueOf(value);
}

public static class Adapter extends TypeAdapter<AutoRenewStatus> {
@Override
public void write(final JsonWriter jsonWriter, final AutoRenewStatus enumeration) throws IOException {
jsonWriter.value(enumeration.getValue());
}

@Override
public AutoRenewStatus read(final JsonReader jsonReader) throws IOException {
Integer value = jsonReader.nextInt();
return AutoRenewStatus.fromValue(value);
}
}
}

Loading

0 comments on commit bd7985f

Please sign in to comment.