Skip to content

Commit 73b2dae

Browse files
authored
Merge branch 'main' into dependabot/maven/cryptoconditions.version-1.0.5
2 parents 221ac8d + 4a01fd4 commit 73b2dae

File tree

54 files changed

+12260
-79
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+12260
-79
lines changed

xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/flags/TransactionFlags.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ public class TransactionFlags extends Flags {
4949
TransactionFlags() {
5050
}
5151

52+
public static TransactionFlags of(long value) {
53+
return new TransactionFlags(value);
54+
}
55+
5256
/**
5357
* Flags indicating that a fully-canonical signature is required. This flag is highly recommended.
5458
*

xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/jackson/modules/AccountTransactionsTransactionDeserializer.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@
2525
import com.fasterxml.jackson.databind.JsonNode;
2626
import com.fasterxml.jackson.databind.ObjectMapper;
2727
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
28+
import com.fasterxml.jackson.databind.node.ObjectNode;
29+
import com.google.common.collect.Lists;
30+
import com.google.common.collect.Sets;
2831
import com.google.common.primitives.UnsignedInteger;
2932
import com.google.common.primitives.UnsignedLong;
3033
import org.xrpl.xrpl4j.model.client.accounts.AccountTransactionsTransaction;
@@ -33,14 +36,18 @@
3336
import org.xrpl.xrpl4j.model.transactions.Transaction;
3437

3538
import java.io.IOException;
39+
import java.util.ArrayList;
3640
import java.util.Optional;
41+
import java.util.Set;
3742

3843
/**
3944
* Custom Jackson Deserializer for {@link AccountTransactionsTransaction}s. This is necessary because Jackson
4045
* does not deserialize {@link com.fasterxml.jackson.annotation.JsonUnwrapped} fields intelligently.
4146
*/
4247
public class AccountTransactionsTransactionDeserializer extends StdDeserializer<AccountTransactionsTransaction<?>> {
4348

49+
public static final Set<String> EXTRA_TRANSACTION_FIELDS = Sets.newHashSet("ledger_index", "date", "hash");
50+
4451
/**
4552
* No-args constructor.
4653
*/
@@ -54,14 +61,20 @@ public AccountTransactionsTransaction<?> deserialize(
5461
DeserializationContext ctxt
5562
) throws IOException {
5663
ObjectMapper objectMapper = (ObjectMapper) jsonParser.getCodec();
57-
JsonNode node = objectMapper.readTree(jsonParser);
64+
ObjectNode node = objectMapper.readTree(jsonParser);
5865

59-
Transaction transaction = objectMapper.readValue(node.toString(), Transaction.class);
6066
long ledgerIndex = node.get("ledger_index").asLong(-1L);
6167
String hash = node.get("hash").asText();
6268
Optional<UnsignedLong> closeDate = Optional.ofNullable(node.get("date"))
6369
.map(JsonNode::asLong)
6470
.map(UnsignedLong::valueOf);
71+
72+
// The Transaction is @JsonUnwrapped in AccountTransactionsTransaction, which means these three fields
73+
// get added to the Transaction.unknownFields Map. To prevent that, we simply remove them from the JSON, because
74+
// they should only show up in AccountTransactionsTransaction
75+
node.remove(EXTRA_TRANSACTION_FIELDS);
76+
Transaction transaction = objectMapper.readValue(node.toString(), Transaction.class);
77+
6578
return AccountTransactionsTransaction.builder()
6679
.transaction(transaction)
6780
.ledgerIndex(LedgerIndex.of(UnsignedInteger.valueOf(ledgerIndex)))

xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/jackson/modules/TransactionDeserializer.java

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99
* Licensed under the Apache License, Version 2.0 (the "License");
1010
* you may not use this file except in compliance with the License.
1111
* You may obtain a copy of the License at
12-
*
12+
*
1313
* http://www.apache.org/licenses/LICENSE-2.0
14-
*
14+
*
1515
* Unless required by applicable law or agreed to in writing, software
1616
* distributed under the License is distributed on an "AS IS" BASIS,
1717
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -27,6 +27,7 @@
2727
import com.fasterxml.jackson.databind.node.ObjectNode;
2828
import org.xrpl.xrpl4j.model.transactions.Transaction;
2929
import org.xrpl.xrpl4j.model.transactions.TransactionType;
30+
import org.xrpl.xrpl4j.model.transactions.UnlModify;
3031

3132
import java.io.IOException;
3233

@@ -45,10 +46,23 @@ protected TransactionDeserializer() {
4546

4647
@Override
4748
public Transaction deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException {
48-
ObjectMapper objectMapper = (ObjectMapper) jsonParser.getCodec();
49-
ObjectNode objectNode = objectMapper.readTree(jsonParser);
49+
final ObjectMapper objectMapper = (ObjectMapper) jsonParser.getCodec();
50+
final ObjectNode objectNode = objectMapper.readTree(jsonParser);
5051

5152
TransactionType transactionType = TransactionType.forValue(objectNode.get("TransactionType").asText());
52-
return objectMapper.treeToValue(objectNode, Transaction.typeMap.inverse().get(transactionType));
53+
final Class<? extends Transaction> transactionTypeClass = Transaction.typeMap.inverse().get(transactionType);
54+
55+
// Fixes #590 by removing the `Account` property from any incoming `UnlModify` JSON about to be deserialized.
56+
// This fixes #590 because the JSON returned by the rippled/clio API v1 has a bug where the account value in
57+
// `UnlModify` transactions is an empty string. When this value is deserialized, an exception is thrown because
58+
// the empty string value is not a valid `Address`. By removing the property from incoming JSON, the Java value
59+
// for the `Account` property is always set to ACCOUNT_ZERO via a default method. One other side effect of this
60+
// fix is that `Account` property will not be errantly added to `unknownFields map of the ultimate Java object,
61+
// which is incorrect.
62+
if (UnlModify.class.isAssignableFrom(transactionTypeClass)) {
63+
objectNode.remove("Account");
64+
}
65+
66+
return objectMapper.treeToValue(objectNode, transactionTypeClass);
5367
}
5468
}

xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/jackson/modules/TransactionResultDeserializer.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import com.fasterxml.jackson.databind.ObjectMapper;
2828
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
2929
import com.fasterxml.jackson.databind.node.ObjectNode;
30+
import com.google.common.collect.Sets;
3031
import com.google.common.primitives.UnsignedInteger;
3132
import com.google.common.primitives.UnsignedLong;
3233
import org.xrpl.xrpl4j.model.client.common.LedgerIndex;
@@ -37,6 +38,7 @@
3738

3839
import java.io.IOException;
3940
import java.util.Optional;
41+
import java.util.Set;
4042

4143
/**
4244
* Custom deserializer for {@link TransactionResult}, which wraps the {@link Transaction} fields in the result JSON.
@@ -48,6 +50,10 @@
4850
*/
4951
public class TransactionResultDeserializer<T extends Transaction> extends StdDeserializer<TransactionResult<T>> {
5052

53+
public static final Set<String> EXTRA_TRANSACTION_FIELDS = Sets.newHashSet(
54+
"ledger_index", "date", "hash", "status", "validated", "meta", "metaData"
55+
);
56+
5157
/**
5258
* No-args constructor.
5359
*/
@@ -60,10 +66,6 @@ public TransactionResult<T> deserialize(JsonParser jsonParser, DeserializationCo
6066
ObjectMapper objectMapper = (ObjectMapper) jsonParser.getCodec();
6167
ObjectNode objectNode = objectMapper.readTree(jsonParser);
6268

63-
JavaType javaType = objectMapper.getTypeFactory().constructType(new TypeReference<T>() {
64-
});
65-
T transaction = objectMapper.convertValue(objectNode, javaType);
66-
6769
LedgerIndex ledgerIndex = objectNode.has("ledger_index") ?
6870
LedgerIndex.of(UnsignedInteger.valueOf(objectNode.get("ledger_index").asInt())) :
6971
null;
@@ -73,6 +75,15 @@ public TransactionResult<T> deserialize(JsonParser jsonParser, DeserializationCo
7375
Optional<TransactionMetadata> metadata = getTransactionMetadata(objectMapper, objectNode);
7476
UnsignedLong closeDate = objectNode.has("date") ? UnsignedLong.valueOf(objectNode.get("date").asLong()) : null;
7577

78+
// The Transaction is @JsonUnwrapped in TransactionResult, which means these fields
79+
// get added to the Transaction.unknownFields Map. To prevent that, we simply remove them from the JSON, because
80+
// they should only show up in AccountTransactionsTransaction
81+
objectNode.remove(EXTRA_TRANSACTION_FIELDS);
82+
83+
JavaType javaType = objectMapper.getTypeFactory().constructType(new TypeReference<T>() {
84+
});
85+
T transaction = objectMapper.convertValue(objectNode, javaType);
86+
7687
return TransactionResult.<T>builder()
7788
.transaction(transaction)
7889
.ledgerIndex(Optional.ofNullable(ledgerIndex))

xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/AmmWithdraw.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ static ImmutableAmmWithdraw.Builder builder() {
9696
*
9797
* @return An optionally present {@link IssuedCurrencyAmount}.
9898
*/
99-
@JsonProperty("LPTokensIn")
99+
@JsonProperty("LPTokenIn")
100100
Optional<CurrencyAmount> lpTokensIn();
101101

102102
}

xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/Transaction.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
* =========================LICENSE_END==================================
2121
*/
2222

23+
import com.fasterxml.jackson.annotation.JsonAnyGetter;
2324
import com.fasterxml.jackson.annotation.JsonInclude;
25+
import com.fasterxml.jackson.annotation.JsonInclude.Include;
2426
import com.fasterxml.jackson.annotation.JsonProperty;
2527
import com.google.common.collect.BiMap;
2628
import com.google.common.collect.ImmutableBiMap;
@@ -30,6 +32,7 @@
3032
import org.xrpl.xrpl4j.crypto.signing.Signature;
3133

3234
import java.util.List;
35+
import java.util.Map;
3336
import java.util.Optional;
3437

3538
/**
@@ -90,6 +93,7 @@ public interface Transaction {
9093
.put(ImmutableDidDelete.class, TransactionType.DID_DELETE)
9194
.put(ImmutableOracleSet.class, TransactionType.ORACLE_SET)
9295
.put(ImmutableOracleDelete.class, TransactionType.ORACLE_DELETE)
96+
.put(ImmutableUnknownTransaction.class, TransactionType.UNKNOWN)
9397
.build();
9498

9599
/**
@@ -106,6 +110,7 @@ public interface Transaction {
106110
* @return A {@link TransactionType}.
107111
*/
108112
@JsonProperty("TransactionType")
113+
@Value.Default // must be Default rather than Derived, otherwise Jackson treats "TransactionType" as an unknownField
109114
default TransactionType transactionType() {
110115
return typeMap.get(this.getClass());
111116
}
@@ -220,4 +225,8 @@ default PublicKey signingPublicKey() {
220225
@JsonProperty("NetworkID")
221226
Optional<NetworkId> networkId();
222227

228+
@JsonAnyGetter
229+
@JsonInclude(Include.NON_ABSENT)
230+
Map<String, Object> unknownFields();
231+
223232
}

xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/TransactionType.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,12 @@ public enum TransactionType {
336336
* is subject to change.</p>
337337
*/
338338
@Beta
339-
ORACLE_DELETE("OracleDelete");
339+
ORACLE_DELETE("OracleDelete"),
340+
341+
/**
342+
* The {@link TransactionType} for any transaction that is unrecognized/unsupported by xrpl4j.
343+
*/
344+
UNKNOWN("Unknown");
340345

341346
private final String value;
342347

@@ -358,7 +363,7 @@ public static TransactionType forValue(String value) {
358363
}
359364
}
360365

361-
throw new IllegalArgumentException("No matching TransactionType enum value for String value " + value);
366+
return UNKNOWN;
362367
}
363368

364369
/**
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package org.xrpl.xrpl4j.model.transactions;
2+
3+
import com.fasterxml.jackson.annotation.JsonIgnore;
4+
import com.fasterxml.jackson.annotation.JsonProperty;
5+
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
6+
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
7+
import org.immutables.value.Value;
8+
import org.immutables.value.Value.Immutable;
9+
import org.xrpl.xrpl4j.model.flags.TransactionFlags;
10+
11+
/**
12+
* Mapping for any transaction type that is unrecognized/unsupported by xrpl4j.
13+
*/
14+
@Immutable
15+
@JsonSerialize(as = ImmutableUnknownTransaction.class)
16+
@JsonDeserialize(as = ImmutableUnknownTransaction.class)
17+
public interface UnknownTransaction extends Transaction {
18+
19+
/**
20+
* Construct a {@code UnknownTransaction} builder.
21+
*
22+
* @return An {@link ImmutableUnknownTransaction.Builder}.
23+
*/
24+
static ImmutableUnknownTransaction.Builder builder() {
25+
return ImmutableUnknownTransaction.builder();
26+
}
27+
28+
/**
29+
* The actual transaction type found in the {@code "TransactionType"} field of the transaction JSON.
30+
*
31+
* <p>This has to be a {@link String} because {@link Transaction#transactionType()} is a {@link TransactionType},
32+
* which only has an UNKNOWN variant. Because this method is also annotated with {@link JsonProperty} of
33+
* "TransactionType", this essentially overrides the "TransactionType" field in JSON, but {@link #transactionType()}
34+
* will always be {@link TransactionType#UNKNOWN} and this field will contain the actual "TransactionType" field.
35+
*
36+
* @return A {@link String} containing the transaction type from JSON.
37+
*/
38+
@JsonProperty("TransactionType")
39+
String unknownTransactionType();
40+
41+
/**
42+
* The {@link TransactionType} of this UnknownTransaction, which will always be {@link TransactionType#UNKNOWN}.
43+
* {@link #unknownTransactionType()} contains the actual transaction type value.
44+
*
45+
* @return {@link TransactionType#UNKNOWN}.
46+
*/
47+
@Override
48+
@JsonIgnore
49+
@Value.Derived
50+
default TransactionType transactionType() {
51+
return Transaction.super.transactionType();
52+
}
53+
54+
/**
55+
* A set of {@link TransactionFlags}.
56+
*
57+
* @return A {@link TransactionFlags}.
58+
*/
59+
@JsonProperty("Flags")
60+
@Value.Default
61+
default TransactionFlags flags() {
62+
return TransactionFlags.EMPTY;
63+
}
64+
65+
}

xrpl4j-core/src/main/java/org/xrpl/xrpl4j/model/transactions/UnlModify.java

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99
* Licensed under the Apache License, Version 2.0 (the "License");
1010
* you may not use this file except in compliance with the License.
1111
* You may obtain a copy of the License at
12-
*
12+
*
1313
* http://www.apache.org/licenses/LICENSE-2.0
14-
*
14+
*
1515
* Unless required by applicable law or agreed to in writing, software
1616
* distributed under the License is distributed on an "AS IS" BASIS,
1717
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -28,8 +28,8 @@
2828
import org.xrpl.xrpl4j.model.client.common.LedgerIndex;
2929

3030
/**
31-
* A {@link UnlModify} pseudo-transaction marks a change to the Negative UNL,
32-
* indicating that a trusted validator has gone offline or come back online.
31+
* A {@link UnlModify} pseudo-transaction marks a change to the Negative UNL, indicating that a trusted validator has
32+
* gone offline or come back online.
3333
*
3434
* @see "https://xrpl.org/unlmodify.html"
3535
*/
@@ -49,36 +49,35 @@ static ImmutableUnlModify.Builder builder() {
4949
return ImmutableUnlModify.builder();
5050
}
5151

52-
5352
/**
54-
* This field is overridden in this class because of a bug in rippled that causes this field to be missing
55-
* in API responses. In other pseudo-transactions such as {@link SetFee} and {@link EnableAmendment}, the rippled
56-
* API sets the {@code account} field to a special XRPL address called ACCOUNT_ZERO, which is the base58
57-
* encoding of the number zero. Because rippled does not set the {@code account} field of the {@link UnlModify}
58-
* pseudo-transaction, this override will always set the field to ACCOUNT_ZERO to avoid deserialization issues
59-
* and to be consistent with other pseudo-transactions.
53+
* This field is overridden in this class because of a bug in rippled that causes this field to be missing in API
54+
* responses. In other pseudo-transactions such as {@link SetFee} and {@link EnableAmendment}, the rippled API sets
55+
* the {@code account} field to a special XRPL address called ACCOUNT_ZERO, which is the base58 encoding of the number
56+
* zero. Because rippled does not set the {@code account} field of the {@link UnlModify} pseudo-transaction, this
57+
* override will always set the field to ACCOUNT_ZERO to avoid deserialization issues and to be consistent with other
58+
* pseudo-transactions.
6059
*
6160
* @return Always returns ACCOUNT_ZERO, which is the base58 encoding of the number zero.
6261
*/
6362
@Override
6463
@JsonProperty("Account")
65-
@Value.Derived
64+
@Value.Default // Must be `Default` not `Derived`, else this field will be serialized into `unknownFields`.
6665
default Address account() {
6766
return ACCOUNT_ZERO;
6867
}
6968

7069
/**
71-
* The {@link LedgerIndex} where this pseudo-transaction appears.
72-
* This distinguishes the pseudo-transaction from other occurrences of the same change.
70+
* The {@link LedgerIndex} where this pseudo-transaction appears. This distinguishes the pseudo-transaction from other
71+
* occurrences of the same change.
7372
*
7473
* @return A {@link LedgerIndex} to indicates where the tx appears.
7574
*/
7675
@JsonProperty("LedgerSequence")
7776
LedgerIndex ledgerSequence();
7877

7978
/**
80-
* If 1, this change represents adding a validator to the Negative UNL. If 0, this change represents
81-
* removing a validator from the Negative UNL.
79+
* If 1, this change represents adding a validator to the Negative UNL. If 0, this change represents removing a
80+
* validator from the Negative UNL.
8281
*
8382
* @return An {@link UnsignedInteger} denoting either 0 or 1.
8483
*/

0 commit comments

Comments
 (0)