Adding support for account and asset deserialization to the GetObjects API call wrapper

develop
Nelson R. Perez 2017-05-11 18:55:16 -05:00
parent 5ff6f29ebd
commit d21fea7cb6
5 changed files with 379 additions and 26 deletions

View File

@ -1,15 +1,23 @@
package de.bitsharesmunich.graphenej;
import com.google.gson.*;
import de.bitsharesmunich.graphenej.interfaces.ByteSerializable;
import de.bitsharesmunich.graphenej.interfaces.JsonSerializable;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import java.io.ByteArrayOutputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import de.bitsharesmunich.graphenej.interfaces.ByteSerializable;
import de.bitsharesmunich.graphenej.interfaces.JsonSerializable;
/**
* Class tha represents a graphene user account.
@ -18,8 +26,39 @@ import java.util.ArrayList;
public class UserAccount extends GrapheneObject implements ByteSerializable, JsonSerializable {
public static final String PROXY_TO_SELF = "1.2.5";
public static final String KEY_MEMBERSHIP_EXPIRATION_DATE = "membership_expiration_date";
public static final String KEY_REGISTRAR = "registrar";
public static final String KEY_REFERRER = "referrer";
public static final String KEY_LIFETIME_REFERRER = "lifetime_referrer";
public static final String KEY_NETWORK_FEE_PERCENTAGE = "network_fee_percentage";
public static final String KEY_LIFETIME_REFERRER_FEE_PERCENTAGE = "lifetime_referrer_fee_percentage";
public static final String KEY_REFERRER_REWARD_PERCENTAGE = "referrer_rewards_percentage";
public static final String KEY_NAME = "name";
public static final String KEY_OWNER = "owner";
public static final String KEY_ACTIVE = "active";
public static final String KEY_OPTIONS = "options";
public static final String KEY_STATISTICS = "statistics";
public static final String KEY_WHITELISTING_ACCOUNTS = "whitelisting_accounts";
public static final String KEY_BLACKLISTING_ACCOUNTS = "blacklisting_accounts";
public static final String KEY_WHITELISTED_ACCOUNTS = "whitelisted_accounts";
public static final String KEY_BLACKLISTED_ACCOUNTS = "blacklisted_accounts";
public static final String KEY_OWNER_SPECIAL_AUTHORITY = "owner_special_authority";
public static final String KEY_ACTIVE_SPECIAL_AUTHORITY = "active_special_authority";
public static final String KEY_N_CONTROL_FLAGS = "top_n_control_flags";
private long membershipExpirationDate;
private String registrar;
private String referrer;
private String lifetimeReferrer;
private long networkFeePercentage;
private long lifetimeReferrerFeePercentage;
private long referrerRewardsPercentage;
private String name;
private Authority owner;
private Authority active;
private AccountOptions options;
private String statistics;
private String accountName;
/**
* Constructor that expects a user account in the string representation.
@ -37,24 +76,24 @@ public class UserAccount extends GrapheneObject implements ByteSerializable, Jso
*/
public UserAccount(String id, String name){
super(id);
this.accountName = name;
this.name = name;
}
/**
* Getter for the account name field.
* @return: The name of this account.
*/
public String getAccountName() {
return accountName;
public String getName() {
return name;
}
/**
* Setter for the account name field.
* @param accountName: The account name.
* @param name: The account name.
*/
public void setAccountName(String accountName) {
this.accountName = accountName;
public void setName(String name) {
this.name = name;
}
@Override
@ -94,6 +133,140 @@ public class UserAccount extends GrapheneObject implements ByteSerializable, Jso
return this.toJsonString();
}
public long getMembershipExpirationDate() {
return membershipExpirationDate;
}
public void setMembershipExpirationDate(long membershipExpirationDate) {
this.membershipExpirationDate = membershipExpirationDate;
}
public String getRegistrar() {
return registrar;
}
public void setRegistrar(String registrar) {
this.registrar = registrar;
}
public String getReferrer() {
return referrer;
}
public void setReferrer(String referrer) {
this.referrer = referrer;
}
public String getLifetimeReferrer() {
return lifetimeReferrer;
}
public void setLifetimeReferrer(String lifetimeReferrer) {
this.lifetimeReferrer = lifetimeReferrer;
}
public long getNetworkFeePercentage() {
return networkFeePercentage;
}
public void setNetworkFeePercentage(long networkFeePercentage) {
this.networkFeePercentage = networkFeePercentage;
}
public long getLifetimeReferrerFeePercentage() {
return lifetimeReferrerFeePercentage;
}
public void setLifetimeReferrerFeePercentage(long lifetimeReferrerFeePercentage) {
this.lifetimeReferrerFeePercentage = lifetimeReferrerFeePercentage;
}
public long getReferrerRewardsPercentage() {
return referrerRewardsPercentage;
}
public void setReferrerRewardsPercentage(long referrerRewardsPercentage) {
this.referrerRewardsPercentage = referrerRewardsPercentage;
}
public Authority getOwner() {
return owner;
}
public void setOwner(Authority owner) {
this.owner = owner;
}
public Authority getActive() {
return active;
}
public void setActive(Authority active) {
this.active = active;
}
public AccountOptions getOptions() {
return options;
}
public void setOptions(AccountOptions options) {
this.options = options;
}
public String getStatistics() {
return statistics;
}
public void setStatistics(String statistics) {
this.statistics = statistics;
}
/**
* Deserializer used to build a UserAccount instance from the full JSON-formatted response obtained
* by the 'get_objects' API call.
*/
public static class UserAccountFullDeserializer implements JsonDeserializer<UserAccount> {
@Override
public UserAccount deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject jsonAccount = json.getAsJsonObject();
SimpleDateFormat dateFormat = new SimpleDateFormat(Util.TIME_DATE_FORMAT);
// Retrieving and deserializing fields
String id = jsonAccount.get(KEY_ID).getAsString();
String name = jsonAccount.get(KEY_NAME).getAsString();
UserAccount userAccount = new UserAccount(id, name);
AccountOptions options = context.deserialize(jsonAccount.get(KEY_OPTIONS), AccountOptions.class);
Authority owner = context.deserialize(jsonAccount.get(KEY_OWNER), Authority.class);
Authority active = context.deserialize(jsonAccount.get(KEY_ACTIVE), Authority.class);
// Setting deserialized fields into the created instance
userAccount.setRegistrar(jsonAccount.get(KEY_REGISTRAR).getAsString());
// Handling the deserialization and assignation of the membership date, which internally
// is stored as a long POSIX time value
try{
Date date = dateFormat.parse(jsonAccount.get(KEY_MEMBERSHIP_EXPIRATION_DATE).getAsString());
userAccount.setMembershipExpirationDate(date.getTime());
} catch (ParseException e) {
System.out.println("ParseException. Msg: "+e.getMessage());
}
// Setting the other fields
userAccount.setReferrer(jsonAccount.get(KEY_REFERRER).getAsString());
userAccount.setLifetimeReferrer(jsonAccount.get(KEY_LIFETIME_REFERRER).getAsString());
userAccount.setNetworkFeePercentage(jsonAccount.get(KEY_NETWORK_FEE_PERCENTAGE).getAsLong());
userAccount.setLifetimeReferrerFeePercentage(jsonAccount.get(KEY_LIFETIME_REFERRER_FEE_PERCENTAGE).getAsLong());
userAccount.setReferrerRewardsPercentage(jsonAccount.get(KEY_REFERRER_REWARD_PERCENTAGE).getAsLong());
userAccount.setOwner(owner);
userAccount.setActive(active);
userAccount.setOptions(options);
userAccount.setStatistics(jsonAccount.get(KEY_STATISTICS).getAsString());
return userAccount;
}
}
/**
* Custom deserializer used to deserialize user accounts provided as response from the 'lookup_accounts' api call.
* This response contains serialized user accounts in the form [[{id1},{name1}][{id1},{name1}]].

View File

@ -1,15 +1,13 @@
package de.bitsharesmunich.graphenej.api;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.google.gson.reflect.TypeToken;
import com.neovisionaries.ws.client.WebSocket;
import com.neovisionaries.ws.client.WebSocketFrame;
import de.bitsharesmunich.graphenej.AssetAmount;
import de.bitsharesmunich.graphenej.RPC;
import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener;
import de.bitsharesmunich.graphenej.models.ApiCall;
import de.bitsharesmunich.graphenej.models.BitAssetData;
import de.bitsharesmunich.graphenej.models.WitnessResponse;
import java.io.Serializable;
import java.lang.reflect.Type;
@ -17,6 +15,18 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import de.bitsharesmunich.graphenej.AccountOptions;
import de.bitsharesmunich.graphenej.Asset;
import de.bitsharesmunich.graphenej.AssetAmount;
import de.bitsharesmunich.graphenej.Authority;
import de.bitsharesmunich.graphenej.GrapheneObject;
import de.bitsharesmunich.graphenej.RPC;
import de.bitsharesmunich.graphenej.UserAccount;
import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener;
import de.bitsharesmunich.graphenej.models.ApiCall;
import de.bitsharesmunich.graphenej.models.BitAssetData;
import de.bitsharesmunich.graphenej.models.WitnessResponse;
/**
* Created by nelson on 1/8/17.
*/
@ -48,16 +58,40 @@ public class GetObjects extends BaseGrapheneHandler {
String response = frame.getPayloadText();
GsonBuilder gsonBuilder = new GsonBuilder();
//TODO: Uncomment this line after the deserializer is implemented.
gsonBuilder.registerTypeAdapter(AssetAmount.class, new AssetAmount.AssetAmountDeserializer());
// gsonBuilder.registerTypeAdapter(BitAssetData.class, new BitAssetData.BitAssetDeserializer());
gsonBuilder.registerTypeAdapter(Asset.class, new Asset.AssetDeserializer());
gsonBuilder.registerTypeAdapter(UserAccount.class, new UserAccount.UserAccountFullDeserializer());
gsonBuilder.registerTypeAdapter(Authority.class, new Authority.AuthorityDeserializer());
gsonBuilder.registerTypeAdapter(AccountOptions.class, new AccountOptions.AccountOptionsDeserializer());
Gson gson = gsonBuilder.create();
// Only homogeneus array is currently supported
if(ids.get(0).split("\\.")[1].equals("4")){
Type BitAssetDataType = new TypeToken<WitnessResponse<List<BitAssetData>>>(){}.getType();
WitnessResponse<List<BitAssetData>> witnessResponse = gsonBuilder.create().fromJson(response, BitAssetDataType);
mListener.onSuccess(witnessResponse);
List<GrapheneObject> parsedResult = new ArrayList<>();
JsonParser parser = new JsonParser();
JsonArray resultArray = parser.parse(response).getAsJsonObject().get(WitnessResponse.KEY_RESULT).getAsJsonArray();
for(JsonElement element : resultArray){
String id = element.getAsJsonObject().get(GrapheneObject.KEY_ID).getAsString();
GrapheneObject grapheneObject = new GrapheneObject(id);
switch (grapheneObject.getObjectType()){
case ASSET_OBJECT:
Asset asset = gson.fromJson(element, Asset.class);
parsedResult.add(asset);
break;
case ACCOUNT_OBJECT:
UserAccount account = gson.fromJson(element, UserAccount.class);
parsedResult.add(account);
break;
case ASSET_BITASSET_DATA:
Type BitAssetDataType = new TypeToken<WitnessResponse<List<BitAssetData>>>(){}.getType();
WitnessResponse<List<BitAssetData>> witnessResponse = gsonBuilder.create().fromJson(response, BitAssetDataType);
BitAssetData bitAssetData = witnessResponse.result.get(0);
parsedResult.add(bitAssetData);
}
}
WitnessResponse<List<GrapheneObject>> output = new WitnessResponse<>();
output.result = parsedResult;
mListener.onSuccess(output);
websocket.disconnect();
}

View File

@ -1,5 +1,6 @@
package de.bitsharesmunich.graphenej.models;
import de.bitsharesmunich.graphenej.GrapheneObject;
import de.bitsharesmunich.graphenej.Price;
/**
@ -8,8 +9,7 @@ import de.bitsharesmunich.graphenej.Price;
*
* Created by nelson on 1/8/17.
*/
public class BitAssetData {
public String id;
public class BitAssetData extends GrapheneObject {
public Object[] feeds;
public AssetFeed current_feed;
public String current_feed_publication_time;
@ -18,4 +18,8 @@ public class BitAssetData {
public boolean is_prediction_market;
public Price settlement_price;
public long settlement_fund;
public BitAssetData(String id) {
super(id);
}
}

View File

@ -4,5 +4,8 @@ package de.bitsharesmunich.graphenej.models;
* Generic witness response
*/
public class WitnessResponse<T> extends BaseResponse{
public static final String KEY_ID = "id";
public static final String KEY_RESULT = "result";
public T result;
}

View File

@ -0,0 +1,139 @@
package de.bitsharesmunich.graphenej.api;
import com.neovisionaries.ws.client.WebSocketException;
import junit.framework.Assert;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import de.bitsharesmunich.graphenej.Asset;
import de.bitsharesmunich.graphenej.GrapheneObject;
import de.bitsharesmunich.graphenej.UserAccount;
import de.bitsharesmunich.graphenej.interfaces.WitnessResponseListener;
import de.bitsharesmunich.graphenej.models.BaseResponse;
import de.bitsharesmunich.graphenej.models.BitAssetData;
import de.bitsharesmunich.graphenej.models.WitnessResponse;
/**
* Testing the {@link GetObjects} API wrapper and its deserialization
*
* Created by nelson on 5/10/17.
*/
public class GetObjectsTest extends BaseApiTest{
private final Asset asset = new Asset("1.3.0", "BTS", 5);
private final UserAccount account = new UserAccount("1.2.116354");
private final String bitAssetId = "2.4.13";
@Test
public void testGetAsset(){
try{
ArrayList<String> ids = new ArrayList<>();
ids.add(asset.getObjectId());
mWebSocket.addListener(new GetObjects(ids, new WitnessResponseListener() {
@Override
public void onSuccess(WitnessResponse response) {
System.out.println("onSuccess");
List<GrapheneObject> result = (List<GrapheneObject>) response.result;
System.out.println("Got " + result.size() + " result");
Assert.assertEquals("Making sure we only get one address back", 1, result.size());
synchronized (GetObjectsTest.this){
GetObjectsTest.this.notifyAll();
}
}
@Override
public void onError(BaseResponse.Error error) {
System.out.println("onError");
synchronized (GetObjectsTest.this){
GetObjectsTest.this.notifyAll();
}
}
}));
mWebSocket.connect();
synchronized (this){
wait();
}
}catch (WebSocketException e) {
System.out.println("WebSocketException. Msg: " + e.getMessage());
} catch (InterruptedException e) {
System.out.println("InterruptedException. Msg: "+e.getMessage());
}
}
@Test
public void testGetAccount(){
try{
ArrayList<String> ids = new ArrayList<>();
ids.add(account.getObjectId());
mWebSocket.addListener(new GetObjects(ids, new WitnessResponseListener() {
@Override
public void onSuccess(WitnessResponse response) {
System.out.println("onSuccess");
List<GrapheneObject> result = (List<GrapheneObject>) response.result;
UserAccount userAccount = (UserAccount) result.get(0);
System.out.println("Account name: "+userAccount.getName());
System.out.println("json string: "+userAccount.toJsonString());
System.out.println("owner: "+userAccount.getOwner().getKeyAuthList().get(0).getAddress());
System.out.println("active: "+userAccount.getActive().getKeyAuthList().get(0).getAddress());
System.out.println("memo: "+userAccount.getOptions().getMemoKey().getAddress());
synchronized (GetObjectsTest.this){
GetObjectsTest.this.notifyAll();
}
}
@Override
public void onError(BaseResponse.Error error) {
System.out.println("onError");
synchronized (GetObjectsTest.this){
GetObjectsTest.this.notifyAll();
}
}
}));
mWebSocket.connect();
synchronized (this){
wait();
}
}catch (WebSocketException e) {
System.out.println("WebSocketException. Msg: " + e.getMessage());
} catch (InterruptedException e) {
System.out.println("InterruptedException. Msg: "+e.getMessage());
}
}
@Test
public void testBitAssetData(){
try{
ArrayList<String> ids = new ArrayList<>();
ids.add(bitAssetId);
mWebSocket.addListener(new GetObjects(ids, new WitnessResponseListener() {
@Override
public void onSuccess(WitnessResponse response) {
System.out.println("onSuccess");
List<GrapheneObject> list = (List<GrapheneObject>) response.result;
BitAssetData bitAssetData = (BitAssetData) list.get(0);
System.out.println("feed time: " + bitAssetData.current_feed_publication_time);
}
@Override
public void onError(BaseResponse.Error error) {
System.out.println("onError");
}
}));
mWebSocket.connect();
synchronized (this){
wait();
}
}catch (WebSocketException e) {
System.out.println("WebSocketException. Msg: " + e.getMessage());
} catch (InterruptedException e) {
System.out.println("InterruptedException. Msg: "+e.getMessage());
} }
}