Implemented deserialization of custom operation

This commit is contained in:
Kostya Shpachenko 2017-12-18 15:39:37 +02:00
parent be9a16a48b
commit d0629eab85
4 changed files with 74 additions and 6 deletions

View file

@ -11,6 +11,7 @@ import com.google.gson.JsonParseException;
import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer; import com.google.gson.JsonSerializer;
import cy.agorise.graphenej.operations.CustomOperation;
import org.bitcoinj.core.DumpedPrivateKey; import org.bitcoinj.core.DumpedPrivateKey;
import org.bitcoinj.core.ECKey; import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.Sha256Hash; import org.bitcoinj.core.Sha256Hash;
@ -343,7 +344,7 @@ public class Transaction implements ByteSerializable, JsonSerializable {
} else if (operationId == OperationType.WORKER_CREATE_OPERATION.ordinal()) { } else if (operationId == OperationType.WORKER_CREATE_OPERATION.ordinal()) {
//TODO: Add operation deserialization support //TODO: Add operation deserialization support
} else if (operationId == OperationType.CUSTOM_OPERATION.ordinal()) { } else if (operationId == OperationType.CUSTOM_OPERATION.ordinal()) {
//TODO: Add operation deserialization support operation = context.deserialize(jsonOperation, CustomOperation.class);
} else if (operationId == OperationType.ASSERT_OPERATION.ordinal()) { } else if (operationId == OperationType.ASSERT_OPERATION.ordinal()) {
//TODO: Add operation deserialization support //TODO: Add operation deserialization support
} else if (operationId == OperationType.BALANCE_CLAIM_OPERATION.ordinal()) { } else if (operationId == OperationType.BALANCE_CLAIM_OPERATION.ordinal()) {

View file

@ -13,6 +13,8 @@ import cy.agorise.graphenej.models.ApiCall;
import cy.agorise.graphenej.models.BaseResponse; import cy.agorise.graphenej.models.BaseResponse;
import cy.agorise.graphenej.models.Block; import cy.agorise.graphenej.models.Block;
import cy.agorise.graphenej.models.WitnessResponse; import cy.agorise.graphenej.models.WitnessResponse;
import cy.agorise.graphenej.operations.CustomOperation;
import cy.agorise.graphenej.operations.LimitOrderCreateOperation;
import cy.agorise.graphenej.operations.TransferOperation; import cy.agorise.graphenej.operations.TransferOperation;
import java.io.Serializable; import java.io.Serializable;
@ -88,6 +90,8 @@ public class GetBlock extends BaseGrapheneHandler {
gson = new GsonBuilder() gson = new GsonBuilder()
.registerTypeAdapter(Transaction.class, new Transaction.TransactionDeserializer()) .registerTypeAdapter(Transaction.class, new Transaction.TransactionDeserializer())
.registerTypeAdapter(TransferOperation.class, new TransferOperation.TransferDeserializer()) .registerTypeAdapter(TransferOperation.class, new TransferOperation.TransferDeserializer())
.registerTypeAdapter(LimitOrderCreateOperation.class, new LimitOrderCreateOperation.LimitOrderCreateDeserializer())
.registerTypeAdapter(CustomOperation.class, new CustomOperation.CustomOperationDeserializer())
.registerTypeAdapter(AssetAmount.class, new AssetAmount.AssetAmountDeserializer()) .registerTypeAdapter(AssetAmount.class, new AssetAmount.AssetAmountDeserializer())
.create(); .create();
WitnessResponse<Block> blockResponse = gson.fromJson(response, BlockResponse); WitnessResponse<Block> blockResponse = gson.fromJson(response, BlockResponse);

View file

@ -26,6 +26,7 @@ import cy.agorise.graphenej.models.DynamicGlobalProperties;
import cy.agorise.graphenej.models.SubscriptionResponse; import cy.agorise.graphenej.models.SubscriptionResponse;
import cy.agorise.graphenej.models.WitnessResponse; import cy.agorise.graphenej.models.WitnessResponse;
import cy.agorise.graphenej.objects.Memo; import cy.agorise.graphenej.objects.Memo;
import cy.agorise.graphenej.operations.CustomOperation;
import cy.agorise.graphenej.operations.LimitOrderCreateOperation; import cy.agorise.graphenej.operations.LimitOrderCreateOperation;
import cy.agorise.graphenej.operations.TransferOperation; import cy.agorise.graphenej.operations.TransferOperation;
@ -89,6 +90,7 @@ public class SubscriptionMessagesHub extends BaseGrapheneHandler implements Subs
builder.registerTypeAdapter(Transaction.class, new Transaction.TransactionDeserializer()); builder.registerTypeAdapter(Transaction.class, new Transaction.TransactionDeserializer());
builder.registerTypeAdapter(TransferOperation.class, new TransferOperation.TransferDeserializer()); builder.registerTypeAdapter(TransferOperation.class, new TransferOperation.TransferDeserializer());
builder.registerTypeAdapter(LimitOrderCreateOperation.class, new LimitOrderCreateOperation.LimitOrderCreateDeserializer()); builder.registerTypeAdapter(LimitOrderCreateOperation.class, new LimitOrderCreateOperation.LimitOrderCreateDeserializer());
builder.registerTypeAdapter(CustomOperation.class, new CustomOperation.CustomOperationDeserializer());
builder.registerTypeAdapter(AssetAmount.class, new AssetAmount.AssetAmountDeserializer()); builder.registerTypeAdapter(AssetAmount.class, new AssetAmount.AssetAmountDeserializer());
builder.registerTypeAdapter(UserAccount.class, new UserAccount.UserAccountSimpleDeserializer()); builder.registerTypeAdapter(UserAccount.class, new UserAccount.UserAccountSimpleDeserializer());
builder.registerTypeAdapter(DynamicGlobalProperties.class, new DynamicGlobalProperties.DynamicGlobalPropertiesDeserializer()); builder.registerTypeAdapter(DynamicGlobalProperties.class, new DynamicGlobalProperties.DynamicGlobalPropertiesDeserializer());

View file

@ -1,18 +1,17 @@
package cy.agorise.graphenej.operations; package cy.agorise.graphenej.operations;
import com.google.common.primitives.Bytes; import com.google.common.primitives.Bytes;
import com.google.gson.JsonArray; import com.google.gson.*;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import cy.agorise.graphenej.*; import cy.agorise.graphenej.*;
import java.lang.reflect.Type;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
public class CustomOperation extends BaseOperation { public class CustomOperation extends BaseOperation {
private static final String KEY_FEE = "fee"; private static final String KEY_FEE = "fee";
private static final String KEY_PAYER = "payer"; private static final String KEY_PAYER = "payer";
private static final String KEY_REQUIRED_AUTH = "required_auths"; private static final String KEY_REQUIRED_AUTHS = "required_auths";
private static final String KEY_ID = "id"; private static final String KEY_ID = "id";
private static final String KEY_DATA = "data"; private static final String KEY_DATA = "data";
@ -113,7 +112,7 @@ public class CustomOperation extends BaseOperation {
requiredAuthArray.add(userAccount.getObjectId()); requiredAuthArray.add(userAccount.getObjectId());
} }
} }
jsonObject.add(KEY_REQUIRED_AUTH, requiredAuthArray); jsonObject.add(KEY_REQUIRED_AUTHS, requiredAuthArray);
jsonObject.addProperty(KEY_ID, operationId); jsonObject.addProperty(KEY_ID, operationId);
jsonObject.addProperty(KEY_DATA, Util.bytesToHex(Util.hexlify(data))); jsonObject.addProperty(KEY_DATA, Util.bytesToHex(Util.hexlify(data)));
@ -121,4 +120,66 @@ public class CustomOperation extends BaseOperation {
return array; return array;
} }
/**
* Deserializer used to convert the JSON-formatted representation of a custom_operation
* into its java object version.
*
* The following is an example of the serialized form of this operation:
*
* [
* 35,
* {
* "fee": {
* "amount": 100000,
* "asset_id": "1.3.0"
* },
* "payer": "1.2.20",
* "required_auths": [
* "1.2.20"
* ],
* "id": 61166,
* "data": "736f6d652064617461"
* }
* ]
*/
public static class CustomOperationDeserializer implements JsonDeserializer<CustomOperation> {
@Override
public CustomOperation deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
if (json.isJsonArray()){
// This block is used just to check if we are in the first step of the deserialization
// when we are dealing with an array.
JsonArray serializedCustomOperation = json.getAsJsonArray();
if (serializedCustomOperation.get(0).getAsInt() != OperationType.CUSTOM_OPERATION.ordinal()){
// If the operation type does not correspond to a custom operation, we return null
return null;
} else {
// Calling itself recursively, this is only done once, so there will be no problems.
return context.deserialize(serializedCustomOperation.get(1), CustomOperation.class);
}
}else{
// This block is called in the second recursion and takes care of deserializing the
// limit order data itself.
JsonObject jsonObject = json.getAsJsonObject();
AssetAmount fee = context.deserialize(jsonObject.get(KEY_FEE), AssetAmount.class);
String payerId = jsonObject.get(KEY_PAYER) .getAsString();
UserAccount payer = new UserAccount(payerId);
List<UserAccount> requiredAuths = new LinkedList<>();
JsonElement requiredAuthsElement = jsonObject.get(KEY_REQUIRED_AUTHS);
if ((requiredAuthsElement != null) && (requiredAuthsElement.isJsonArray())) {
JsonArray requiredAuthsArray = requiredAuthsElement.getAsJsonArray();
for (JsonElement jsonElement : requiredAuthsArray) {
String userAccountId = jsonElement.getAsString();
requiredAuths.add(new UserAccount(userAccountId));
}
}
int operationId = jsonObject.get(KEY_ID).getAsInt();
String data = new String(Util.hexToBytes(jsonObject.get(KEY_DATA).getAsString()));
return new CustomOperation(fee, payer, operationId, requiredAuths, data);
}
}
}
} }