Introducing the SkipAssetOptionsStrategy class, used to avoid falling into an infinite loop while deserializing/serializing results from the get_relative_account_history API call

This commit is contained in:
Nelson R. Perez 2018-06-11 23:48:35 -05:00
parent 7582fefd0e
commit 4f6b628891
3 changed files with 88 additions and 51 deletions

View file

@ -10,6 +10,7 @@ import java.util.List;
import cy.agorise.graphenej.AccountOptions; import cy.agorise.graphenej.AccountOptions;
import cy.agorise.graphenej.AssetAmount; import cy.agorise.graphenej.AssetAmount;
import cy.agorise.graphenej.AssetOptions;
import cy.agorise.graphenej.Authority; import cy.agorise.graphenej.Authority;
import cy.agorise.graphenej.Transaction; import cy.agorise.graphenej.Transaction;
import cy.agorise.graphenej.api.calls.GetAccounts; import cy.agorise.graphenej.api.calls.GetAccounts;
@ -51,7 +52,7 @@ public class DeserializationMap {
// GetAccounts // GetAccounts
mClassMap.put(GetAccounts.class, List.class); mClassMap.put(GetAccounts.class, List.class);
Gson getAccountsGson = new GsonBuilder() Gson getAccountsGson = new GsonBuilder()
.setExclusionStrategies(new GetAccountsExclusionStrategy()) .setExclusionStrategies(new SkipAccountOptionsStrategy())
.registerTypeAdapter(Authority.class, new Authority.AuthorityDeserializer()) .registerTypeAdapter(Authority.class, new Authority.AuthorityDeserializer())
.registerTypeAdapter(AccountOptions.class, new AccountOptions.AccountOptionsDeserializer()) .registerTypeAdapter(AccountOptions.class, new AccountOptions.AccountOptionsDeserializer())
.create(); .create();
@ -64,9 +65,10 @@ public class DeserializationMap {
.create(); .create();
mGsonMap.put(GetRequiredFees.class, getRequiredFeesGson); mGsonMap.put(GetRequiredFees.class, getRequiredFeesGson);
// GetRelativeAccounthistory // GetRelativeAccountHistory
mClassMap.put(GetRelativeAccountHistory.class, List.class); mClassMap.put(GetRelativeAccountHistory.class, List.class);
Gson getRelativeAcountHistoryGson = new GsonBuilder() Gson getRelativeAcountHistoryGson = new GsonBuilder()
.setExclusionStrategies(new SkipAccountOptionsStrategy(), new SkipAssetOptionsStrategy())
.registerTypeAdapter(OperationHistory.class, new OperationHistory.OperationHistoryDeserializer()) .registerTypeAdapter(OperationHistory.class, new OperationHistory.OperationHistoryDeserializer())
.registerTypeAdapter(TransferOperation.class, new TransferOperation.TransferDeserializer()) .registerTypeAdapter(TransferOperation.class, new TransferOperation.TransferDeserializer())
.registerTypeAdapter(AssetAmount.class, new AssetAmount.AssetAmountDeserializer()) .registerTypeAdapter(AssetAmount.class, new AssetAmount.AssetAmountDeserializer())
@ -88,7 +90,7 @@ public class DeserializationMap {
* This class is required in order to break a recursion loop when de-serializing the * This class is required in order to break a recursion loop when de-serializing the
* AccountProperties class instance. * AccountProperties class instance.
*/ */
private class GetAccountsExclusionStrategy implements ExclusionStrategy { public static class SkipAccountOptionsStrategy implements ExclusionStrategy {
@Override @Override
public boolean shouldSkipField(FieldAttributes f) { public boolean shouldSkipField(FieldAttributes f) {
@ -100,4 +102,21 @@ public class DeserializationMap {
return clazz == AccountOptions.class; return clazz == AccountOptions.class;
} }
} }
/**
* This class is required in order to break a recursion loop when de-serializing the
* AssetAmount instance.
*/
public static class SkipAssetOptionsStrategy implements ExclusionStrategy {
@Override
public boolean shouldSkipField(FieldAttributes f) {
return false;
}
@Override
public boolean shouldSkipClass(Class<?> clazz) {
return clazz == AssetOptions.class;
}
}
} }

View file

@ -32,7 +32,6 @@ import cy.agorise.graphenej.interfaces.JsonSerializable;
* {@url https://bitshares.org/doxygen/structgraphene_1_1chain_1_1memo__data.html} * {@url https://bitshares.org/doxygen/structgraphene_1_1chain_1_1memo__data.html}
*/ */
public class Memo implements ByteSerializable, JsonSerializable { public class Memo implements ByteSerializable, JsonSerializable {
public final static String TAG = "Memo";
public static final String KEY_FROM = "from"; public static final String KEY_FROM = "from";
public static final String KEY_TO = "to"; public static final String KEY_TO = "to";
public static final String KEY_NONCE = "nonce"; public static final String KEY_NONCE = "nonce";
@ -291,13 +290,15 @@ public class Memo implements ByteSerializable, JsonSerializable {
memoObject.addProperty(KEY_FROM, ""); memoObject.addProperty(KEY_FROM, "");
memoObject.addProperty(KEY_TO, ""); memoObject.addProperty(KEY_TO, "");
memoObject.addProperty(KEY_NONCE, ""); memoObject.addProperty(KEY_NONCE, "");
memoObject.addProperty(KEY_MESSAGE, Util.bytesToHex(this.message)); if(this.message != null)
memoObject.addProperty(KEY_MESSAGE, Util.bytesToHex(this.message));
return null; return null;
}else{ }else{
memoObject.addProperty(KEY_FROM, this.from.toString()); memoObject.addProperty(KEY_FROM, this.from.toString());
memoObject.addProperty(KEY_TO, this.to.toString()); memoObject.addProperty(KEY_TO, this.to.toString());
memoObject.addProperty(KEY_NONCE, String.format("%x", this.nonce)); memoObject.addProperty(KEY_NONCE, String.format("%x", this.nonce));
memoObject.addProperty(KEY_MESSAGE, Util.bytesToHex(this.message)); if(this.message != null)
memoObject.addProperty(KEY_MESSAGE, Util.bytesToHex(this.message));
} }
return memoObject; return memoObject;
} }
@ -310,8 +311,9 @@ public class Memo implements ByteSerializable, JsonSerializable {
*/ */
public JsonElement toJson(boolean decimal){ public JsonElement toJson(boolean decimal){
JsonElement jsonElement = toJsonObject(); JsonElement jsonElement = toJsonObject();
if(decimal){ if(decimal && jsonElement != null){
JsonObject jsonObject = (JsonObject) jsonElement; JsonObject jsonObject = (JsonObject) jsonElement;
// The nonce is interpreted in base 16, but it is going to be written in base 10
BigInteger nonce = new BigInteger(jsonObject.get(KEY_NONCE).getAsString(), 16); BigInteger nonce = new BigInteger(jsonObject.get(KEY_NONCE).getAsString(), 16);
jsonObject.addProperty(KEY_NONCE, nonce.toString()); jsonObject.addProperty(KEY_NONCE, nonce.toString());
} }

View file

@ -9,7 +9,7 @@
android:id="@+id/output_text_container" android:id="@+id/output_text_container"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/container_get_accounts_call" app:layout_constraintBottom_toTopOf="@+id/container_controls"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"> app:layout_constraintTop_toTopOf="parent">
@ -18,52 +18,68 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" /> android:layout_height="match_parent" />
</ScrollView> </ScrollView>
<LinearLayout <ScrollView
android:id="@+id/container_get_accounts_call" android:id="@+id/container_controls"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="0dp"
android:orientation="horizontal"
android:gravity="center"
app:layout_constraintBottom_toTopOf="@+id/container_get_block_call"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/output_text_container"> app:layout_constraintTop_toBottomOf="@id/output_text_container"
<Button app:layout_constraintBottom_toTopOf="@+id/next_activity">
android:id="@+id/call_get_accounts" <LinearLayout
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Get accounts" android:orientation="vertical">
app:layout_constraintBottom_toTopOf="@+id/next_activity" <LinearLayout
app:layout_constraintLeft_toLeftOf="parent" android:layout_width="match_parent"
app:layout_constraintRight_toRightOf="parent" android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/container_get_block_call" /> android:orientation="horizontal"
<EditText android:gravity="center">
android:id="@+id/argument_get_accounts" <Button
android:layout_width="wrap_content" android:id="@+id/call_get_accounts"
android:layout_height="wrap_content" android:layout_width="wrap_content"
android:text="1.2.139205"/> android:layout_height="wrap_content"
</LinearLayout> android:text="Get accounts" />
<LinearLayout <EditText
android:id="@+id/container_get_block_call" android:id="@+id/argument_get_accounts"
android:layout_width="0dp" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" android:text="1.2.139205"/>
android:gravity="center" </LinearLayout>
app:layout_constraintBottom_toTopOf="@+id/next_activity" <LinearLayout
app:layout_constraintLeft_toLeftOf="parent" android:layout_width="match_parent"
app:layout_constraintRight_toRightOf="parent" android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/container_get_accounts_call"> android:orientation="horizontal"
<Button android:gravity="center">
android:id="@+id/call_get_block" <Button
android:layout_width="wrap_content" android:id="@+id/call_get_block"
android:layout_height="wrap_content" android:layout_width="wrap_content"
android:text="Get block"/> android:layout_height="wrap_content"
<EditText android:text="Get block"/>
android:id="@+id/argument_get_block" <EditText
android:layout_width="wrap_content" android:id="@+id/argument_get_block"
android:layout_height="wrap_content" android:layout_width="wrap_content"
android:text="100000"/> android:layout_height="wrap_content"
</LinearLayout> android:text="100000"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center">
<Button
android:id="@+id/call_get_relative_account_history"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Get relative account history"/>
<EditText
android:id="@+id/argument_get_relative_account_history"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1.2.138632"/>
</LinearLayout>
</LinearLayout>
</ScrollView>
<Button <Button
android:id="@+id/next_activity" android:id="@+id/next_activity"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -72,7 +88,7 @@
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/container_get_block_call" /> app:layout_constraintTop_toBottomOf="@id/container_controls" />
<TextView <TextView
android:id="@+id/connection_status" android:id="@+id/connection_status"
android:layout_width="match_parent" android:layout_width="match_parent"