Skip to content

Commit a589c2a

Browse files
authored
refactor: use static initialization for GsonSingleton. (#757)
Replace lazy initialization with static initialization to ensure thread safety. The previous implementation had a race condition where multiple threads could create separate Gson instances.
1 parent b3c89a2 commit a589c2a

2 files changed

Lines changed: 46 additions & 49 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- fix: add overflow check in `TimeBounds.expiresAfter()` to prevent integer overflow when timeout is too large.
99
- fix: add validation for `ManageDataOperation` value length to ensure it does not exceed 64 bytes.
1010
- fix: use `StandardCharsets.UTF_8` explicitly when converting byte arrays to strings to ensure consistent behavior across different platforms.
11+
- refactor: use static initialization for `GsonSingleton` to ensure thread safety.
1112

1213
## 2.2.1
1314

src/main/java/org/stellar/sdk/responses/gson/GsonSingleton.java

Lines changed: 45 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -26,58 +26,54 @@
2626
* <p>Usually, you shouldn't need to use this class directly.
2727
*/
2828
public class GsonSingleton {
29-
private static Gson instance = null;
29+
private static final Gson INSTANCE = createInstance();
3030

31-
protected GsonSingleton() {}
31+
private GsonSingleton() {}
3232

3333
public static Gson getInstance() {
34-
if (instance == null) {
35-
TypeToken<Page<AccountResponse>> accountPageType = new TypeToken<Page<AccountResponse>>() {};
36-
TypeToken<Page<AssetResponse>> assetPageType = new TypeToken<Page<AssetResponse>>() {};
37-
TypeToken<Page<EffectResponse>> effectPageType = new TypeToken<Page<EffectResponse>>() {};
38-
TypeToken<Page<LedgerResponse>> ledgerPageType = new TypeToken<Page<LedgerResponse>>() {};
39-
TypeToken<Page<LiquidityPoolResponse>> liquidityPoolPageType =
40-
new TypeToken<Page<LiquidityPoolResponse>>() {};
41-
TypeToken<Page<OfferResponse>> offerPageType = new TypeToken<Page<OfferResponse>>() {};
42-
TypeToken<Page<OperationResponse>> operationPageType =
43-
new TypeToken<Page<OperationResponse>>() {};
44-
TypeToken<Page<PathResponse>> pathPageType = new TypeToken<Page<PathResponse>>() {};
45-
TypeToken<Page<TradeResponse>> tradePageType = new TypeToken<Page<TradeResponse>>() {};
46-
TypeToken<Page<TradeAggregationResponse>> tradeAggregationPageType =
47-
new TypeToken<Page<TradeAggregationResponse>>() {};
48-
TypeToken<Page<TransactionResponse>> transactionPageType =
49-
new TypeToken<Page<TransactionResponse>>() {};
50-
TypeToken<Page<ClaimableBalanceResponse>> claimableBalancePageType =
51-
new TypeToken<Page<ClaimableBalanceResponse>>() {};
34+
return INSTANCE;
35+
}
36+
37+
private static Gson createInstance() {
38+
TypeToken<Page<AccountResponse>> accountPageType = new TypeToken<Page<AccountResponse>>() {};
39+
TypeToken<Page<AssetResponse>> assetPageType = new TypeToken<Page<AssetResponse>>() {};
40+
TypeToken<Page<EffectResponse>> effectPageType = new TypeToken<Page<EffectResponse>>() {};
41+
TypeToken<Page<LedgerResponse>> ledgerPageType = new TypeToken<Page<LedgerResponse>>() {};
42+
TypeToken<Page<LiquidityPoolResponse>> liquidityPoolPageType =
43+
new TypeToken<Page<LiquidityPoolResponse>>() {};
44+
TypeToken<Page<OfferResponse>> offerPageType = new TypeToken<Page<OfferResponse>>() {};
45+
TypeToken<Page<OperationResponse>> operationPageType =
46+
new TypeToken<Page<OperationResponse>>() {};
47+
TypeToken<Page<PathResponse>> pathPageType = new TypeToken<Page<PathResponse>>() {};
48+
TypeToken<Page<TradeResponse>> tradePageType = new TypeToken<Page<TradeResponse>>() {};
49+
TypeToken<Page<TradeAggregationResponse>> tradeAggregationPageType =
50+
new TypeToken<Page<TradeAggregationResponse>>() {};
51+
TypeToken<Page<TransactionResponse>> transactionPageType =
52+
new TypeToken<Page<TransactionResponse>>() {};
53+
TypeToken<Page<ClaimableBalanceResponse>> claimableBalancePageType =
54+
new TypeToken<Page<ClaimableBalanceResponse>>() {};
5255

53-
instance =
54-
new GsonBuilder()
55-
.registerTypeAdapter(Asset.class, new AssetDeserializer())
56-
.registerTypeAdapter(Predicate.class, new PredicateDeserializer())
57-
.registerTypeAdapter(OperationResponse.class, new OperationDeserializer())
58-
.registerTypeAdapter(EffectResponse.class, new EffectDeserializer())
59-
.registerTypeAdapter(
60-
accountPageType.getType(), new PageDeserializer<>(accountPageType))
61-
.registerTypeAdapter(assetPageType.getType(), new PageDeserializer<>(assetPageType))
62-
.registerTypeAdapter(effectPageType.getType(), new PageDeserializer<>(effectPageType))
63-
.registerTypeAdapter(ledgerPageType.getType(), new PageDeserializer<>(ledgerPageType))
64-
.registerTypeAdapter(
65-
liquidityPoolPageType.getType(), new PageDeserializer<>(liquidityPoolPageType))
66-
.registerTypeAdapter(offerPageType.getType(), new PageDeserializer<>(offerPageType))
67-
.registerTypeAdapter(
68-
operationPageType.getType(), new PageDeserializer<>(operationPageType))
69-
.registerTypeAdapter(pathPageType.getType(), new PageDeserializer<>(pathPageType))
70-
.registerTypeAdapter(tradePageType.getType(), new PageDeserializer<>(tradePageType))
71-
.registerTypeAdapter(
72-
tradeAggregationPageType.getType(),
73-
new PageDeserializer<>(tradeAggregationPageType))
74-
.registerTypeAdapter(
75-
transactionPageType.getType(), new PageDeserializer<>(transactionPageType))
76-
.registerTypeAdapter(
77-
claimableBalancePageType.getType(),
78-
new PageDeserializer<>(claimableBalancePageType))
79-
.create();
80-
}
81-
return instance;
56+
return new GsonBuilder()
57+
.registerTypeAdapter(Asset.class, new AssetDeserializer())
58+
.registerTypeAdapter(Predicate.class, new PredicateDeserializer())
59+
.registerTypeAdapter(OperationResponse.class, new OperationDeserializer())
60+
.registerTypeAdapter(EffectResponse.class, new EffectDeserializer())
61+
.registerTypeAdapter(accountPageType.getType(), new PageDeserializer<>(accountPageType))
62+
.registerTypeAdapter(assetPageType.getType(), new PageDeserializer<>(assetPageType))
63+
.registerTypeAdapter(effectPageType.getType(), new PageDeserializer<>(effectPageType))
64+
.registerTypeAdapter(ledgerPageType.getType(), new PageDeserializer<>(ledgerPageType))
65+
.registerTypeAdapter(
66+
liquidityPoolPageType.getType(), new PageDeserializer<>(liquidityPoolPageType))
67+
.registerTypeAdapter(offerPageType.getType(), new PageDeserializer<>(offerPageType))
68+
.registerTypeAdapter(operationPageType.getType(), new PageDeserializer<>(operationPageType))
69+
.registerTypeAdapter(pathPageType.getType(), new PageDeserializer<>(pathPageType))
70+
.registerTypeAdapter(tradePageType.getType(), new PageDeserializer<>(tradePageType))
71+
.registerTypeAdapter(
72+
tradeAggregationPageType.getType(), new PageDeserializer<>(tradeAggregationPageType))
73+
.registerTypeAdapter(
74+
transactionPageType.getType(), new PageDeserializer<>(transactionPageType))
75+
.registerTypeAdapter(
76+
claimableBalancePageType.getType(), new PageDeserializer<>(claimableBalancePageType))
77+
.create();
8278
}
8379
}

0 commit comments

Comments
 (0)