-
Notifications
You must be signed in to change notification settings - Fork 572
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix deserialization logic for polymorphic types
- Loading branch information
Showing
25 changed files
with
388 additions
and
296 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
3 changes: 0 additions & 3 deletions
3
src/Stripe.net/Entities/PaymentIntents/PaymentIntentSourceAction.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
51 changes: 0 additions & 51 deletions
51
src/Stripe.net/Infrastructure/JsonConverters/AbstractStripeObjectConverter.cs
This file was deleted.
Oops, something went wrong.
24 changes: 0 additions & 24 deletions
24
src/Stripe.net/Infrastructure/JsonConverters/BalanceTransactionSourceConverter.cs
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
15 changes: 0 additions & 15 deletions
15
src/Stripe.net/Infrastructure/JsonConverters/ExternalAccountConverter.cs
This file was deleted.
Oops, something went wrong.
17 changes: 0 additions & 17 deletions
17
src/Stripe.net/Infrastructure/JsonConverters/PaymentSourceConverter.cs
This file was deleted.
Oops, something went wrong.
140 changes: 73 additions & 67 deletions
140
src/Stripe.net/Infrastructure/JsonConverters/StripeObjectConverter.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,77 +1,83 @@ | ||
namespace Stripe.Infrastructure | ||
{ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Reflection; | ||
using Newtonsoft.Json; | ||
using Newtonsoft.Json.Linq; | ||
|
||
/// <summary> | ||
/// This converter is used to deserialize attributes declared as `IHasObject` into concrete | ||
/// model classes. In other words, this converter can deserialize any Stripe object based on | ||
/// the value of the <c>object</c> attribute. This is useful when the type of the object has | ||
/// to be determined at runtime, such as when decoding the <c>data.object</c> attribute of | ||
/// event objects. | ||
/// This converter can be used to deserialize any Stripe object. It is mainly useful for | ||
/// polymorphic attributes, when the property's type is an interface instead of a concrete type. | ||
/// In this case, the converter will use the value of the `object` key in the JSON payload to | ||
/// decide which concrete type to instantiate. If no concrete type is found (or if one is found, | ||
/// but it's not compatible with the expected interface), then the converter returns `null`. | ||
/// </summary> | ||
internal class StripeObjectConverter : AbstractStripeObjectConverter<IHasObject> | ||
public class StripeObjectConverter : JsonConverter | ||
{ | ||
protected override Dictionary<string, Func<string, IHasObject>> ObjectsToMapperFuncs | ||
=> new Dictionary<string, Func<string, IHasObject>>() | ||
/// <summary> | ||
/// Gets a value indicating whether this <see cref="JsonConverter"/> can write JSON. | ||
/// </summary> | ||
/// <value> | ||
/// <c>true</c> if this <see cref="JsonConverter"/> can write JSON; otherwise, <c>false</c>. | ||
/// </value> | ||
public override bool CanWrite => false; | ||
|
||
/// <summary> | ||
/// Writes the JSON representation of the object. | ||
/// </summary> | ||
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param> | ||
/// <param name="value">The value.</param> | ||
/// <param name="serializer">The calling serializer.</param> | ||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) | ||
{ | ||
throw new NotSupportedException("StripeObjectConverter should only be used while deserializing."); | ||
} | ||
|
||
/// <summary> | ||
/// Reads the JSON representation of the object. | ||
/// </summary> | ||
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param> | ||
/// <param name="objectType">Type of the object.</param> | ||
/// <param name="existingValue">The existing value of object being read.</param> | ||
/// <param name="serializer">The calling serializer.</param> | ||
/// <returns>The object value.</returns> | ||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) | ||
{ | ||
if (reader.TokenType == JsonToken.Null) | ||
{ | ||
return null; | ||
} | ||
|
||
var jsonObject = JObject.Load(reader); | ||
var objectValue = (string)jsonObject["object"]; | ||
|
||
Type concreteType = Util.GetConcreteType(objectType, objectValue); | ||
if (concreteType == null) | ||
{ | ||
// Couldn't find a concrete type to instantiate, return null. | ||
return null; | ||
} | ||
|
||
var value = Activator.CreateInstance(concreteType); | ||
|
||
using (var subReader = jsonObject.CreateReader()) | ||
{ | ||
serializer.Populate(subReader, value); | ||
} | ||
|
||
return value; | ||
} | ||
|
||
/// <summary> | ||
/// Determines whether this instance can convert the specified object type. | ||
/// </summary> | ||
/// <param name="objectType">Type of the object.</param> | ||
/// <returns> | ||
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>. | ||
/// </returns> | ||
public override bool CanConvert(Type objectType) | ||
{ | ||
{ "account", Mapper<Account>.MapFromJson }, | ||
{ "apple_pay_domain", Mapper<ApplePayDomain>.MapFromJson }, | ||
{ "application_fee", Mapper<ApplicationFee>.MapFromJson }, | ||
{ "balance", Mapper<Balance>.MapFromJson }, | ||
{ "balance_transaction", Mapper<BalanceTransaction>.MapFromJson }, | ||
{ "bank_account", Mapper<BankAccount>.MapFromJson }, | ||
{ "card", Mapper<Card>.MapFromJson }, | ||
{ "charge", Mapper<Charge>.MapFromJson }, | ||
{ "country_spec", Mapper<CountrySpec>.MapFromJson }, | ||
{ "coupon", Mapper<Coupon>.MapFromJson }, | ||
{ "customer", Mapper<Customer>.MapFromJson }, | ||
{ "discount", Mapper<Discount>.MapFromJson }, | ||
{ "dispute", Mapper<Dispute>.MapFromJson }, | ||
{ "ephemeral_key", Mapper<EphemeralKey>.MapFromJson }, | ||
{ "event", Mapper<Event>.MapFromJson }, | ||
{ "exchange_rate", Mapper<ExchangeRate>.MapFromJson }, | ||
{ "fee_refund", Mapper<ApplicationFeeRefund>.MapFromJson }, | ||
{ "file", Mapper<File>.MapFromJson }, | ||
{ "file_link", Mapper<FileLink>.MapFromJson }, | ||
{ "invoice", Mapper<Invoice>.MapFromJson }, | ||
{ "invoiceitem", Mapper<InvoiceItem>.MapFromJson }, | ||
{ "issuing.authorization", Mapper<Issuing.Authorization>.MapFromJson }, | ||
{ "issuing.cardholder", Mapper<Issuing.Cardholder>.MapFromJson }, | ||
{ "issuing.card", Mapper<Issuing.Card>.MapFromJson }, | ||
{ "issuing.dispute", Mapper<Issuing.Dispute>.MapFromJson }, | ||
{ "issuing.transaction", Mapper<Issuing.Transaction>.MapFromJson }, | ||
{ "login_link", Mapper<LoginLink>.MapFromJson }, | ||
{ "order", Mapper<Order>.MapFromJson }, | ||
{ "order_item", Mapper<OrderItem>.MapFromJson }, | ||
{ "order_return", Mapper<OrderReturn>.MapFromJson }, | ||
{ "payment_intent", Mapper<PaymentIntent>.MapFromJson }, | ||
{ "payout", Mapper<Payout>.MapFromJson }, | ||
{ "plan", Mapper<Plan>.MapFromJson }, | ||
{ "product", Mapper<Product>.MapFromJson }, | ||
{ "radar.value_list", Mapper<Radar.ValueList>.MapFromJson }, | ||
{ "radar.value_list_item", Mapper<Radar.ValueListItem>.MapFromJson }, | ||
{ "recipient", Mapper<Recipient>.MapFromJson }, | ||
{ "refund", Mapper<Refund>.MapFromJson }, | ||
{ "reporting.report_run", Mapper<Reporting.ReportRun>.MapFromJson }, | ||
{ "reporting.report_type", Mapper<Reporting.ReportType>.MapFromJson }, | ||
{ "scheduled_query_run", Mapper<Sigma.ScheduledQueryRun>.MapFromJson }, | ||
{ "sku", Mapper<Sku>.MapFromJson }, | ||
{ "source", Mapper<Source>.MapFromJson }, | ||
{ "source_mandate_notification", Mapper<SourceMandateNotification>.MapFromJson }, | ||
{ "source_transaction", Mapper<SourceTransaction>.MapFromJson }, | ||
{ "subscription", Mapper<Subscription>.MapFromJson }, | ||
{ "subscription_item", Mapper<SubscriptionItem>.MapFromJson }, | ||
{ "terminal.connection_token", Mapper<Terminal.ConnectionToken>.MapFromJson }, | ||
{ "terminal.location", Mapper<Terminal.Location>.MapFromJson }, | ||
{ "terminal.reader", Mapper<Terminal.Reader>.MapFromJson }, | ||
{ "three_d_secure", Mapper<ThreeDSecure>.MapFromJson }, | ||
{ "token", Mapper<Token>.MapFromJson }, | ||
{ "topup", Mapper<Topup>.MapFromJson }, | ||
{ "transfer", Mapper<Transfer>.MapFromJson }, | ||
{ "transfer_reversal", Mapper<TransferReversal>.MapFromJson }, | ||
{ "usage_record", Mapper<UsageRecord>.MapFromJson }, | ||
{ "usage_record_summary", Mapper<UsageRecordSummary>.MapFromJson }, | ||
}; | ||
return objectType.GetTypeInfo().IsInterface; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.