From 5443e41881214703f8e685ed27cb4cb5e77599c2 Mon Sep 17 00:00:00 2001
From: ghubstan <36207203+ghubstan@users.noreply.github.com>
Date: Thu, 5 Nov 2020 13:13:17 -0300
Subject: [PATCH 1/8] Add is instanceof CountryBasedPaymentAccount check to
PaymentAccount
(Ask the account instance what it is.)
---
core/src/main/java/bisq/core/payment/PaymentAccount.java | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/core/src/main/java/bisq/core/payment/PaymentAccount.java b/core/src/main/java/bisq/core/payment/PaymentAccount.java
index b38649ef942..f94811585f1 100644
--- a/core/src/main/java/bisq/core/payment/PaymentAccount.java
+++ b/core/src/main/java/bisq/core/payment/PaymentAccount.java
@@ -173,6 +173,10 @@ public String getOwnerId() {
return paymentAccountPayload.getOwnerId();
}
+ public boolean isCountryBasedPaymentAccount() {
+ return this instanceof CountryBasedPaymentAccount;
+ }
+
public boolean isHalCashAccount() {
return this instanceof HalCashAccount;
}
From 0f3b61e2fa5425f6565a0e63bec2db48f5f93249 Mon Sep 17 00:00:00 2001
From: ghubstan <36207203+ghubstan@users.noreply.github.com>
Date: Thu, 5 Nov 2020 13:15:34 -0300
Subject: [PATCH 2/8] Add ReflectionUtils to :common.util pkg
---
.../bisq/common/util/ReflectionUtils.java | 108 ++++++++++++++++++
1 file changed, 108 insertions(+)
create mode 100644 common/src/main/java/bisq/common/util/ReflectionUtils.java
diff --git a/common/src/main/java/bisq/common/util/ReflectionUtils.java b/common/src/main/java/bisq/common/util/ReflectionUtils.java
new file mode 100644
index 00000000000..e70162ecb23
--- /dev/null
+++ b/common/src/main/java/bisq/common/util/ReflectionUtils.java
@@ -0,0 +1,108 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see .
+ */
+
+package bisq.common.util;
+
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+import static java.util.Arrays.stream;
+import static org.apache.commons.lang3.StringUtils.capitalize;
+
+public class ReflectionUtils {
+
+ /**
+ * Recursively loads a list of fields for a given class and its superclasses,
+ * using a filter predicate to exclude any unwanted fields.
+ *
+ * @param fields The list of fields being loaded for a class hierarchy.
+ * @param clazz The lowest level class in a hierarchy; excluding Object.class.
+ * @param isExcludedField The field exclusion predicate.
+ */
+ public static void loadFieldListForClassHierarchy(List fields,
+ Class> clazz,
+ Predicate isExcludedField) {
+ fields.addAll(stream(clazz.getDeclaredFields())
+ .filter(f -> !isExcludedField.test(f))
+ .collect(Collectors.toList()));
+
+ Class> superclass = clazz.getSuperclass();
+ if (!Objects.equals(superclass, Object.class))
+ loadFieldListForClassHierarchy(fields,
+ superclass,
+ isExcludedField);
+ }
+
+ /**
+ * Returns an Optional of a setter method for a given field and a class hierarchy,
+ * or Optional.empty() if it does not exist.
+ *
+ * @param field The field used to find a setter method.
+ * @param clazz The lowest level class in a hierarchy; excluding Object.class.
+ * @return Optional of the setter method for a field in the class hierarchy,
+ * or Optional.empty() if it does not exist.
+ */
+ public static Optional getSetterMethodForFieldInClassHierarchy(Field field,
+ Class> clazz) {
+ Optional setter = stream(clazz.getDeclaredMethods())
+ .filter((m) -> isSetterForField(m, field))
+ .findFirst();
+
+ if (setter.isPresent())
+ return setter;
+
+ Class> superclass = clazz.getSuperclass();
+ if (!Objects.equals(superclass, Object.class)) {
+ setter = getSetterMethodForFieldInClassHierarchy(field, superclass);
+ if (setter.isPresent())
+ return setter;
+ }
+
+ return Optional.empty();
+ }
+
+ public static boolean isSetterForField(Method m, Field f) {
+ return m.getName().startsWith("set")
+ && m.getName().endsWith(capitalize(f.getName()))
+ && m.getReturnType().getName().equals("void")
+ && m.getParameterCount() == 1
+ && m.getParameterTypes()[0].getName().equals(f.getType().getName());
+ }
+
+ public static boolean isSetterOnClass(Method setter, Class> clazz) {
+ return clazz.equals(setter.getDeclaringClass());
+ }
+
+ public static String getVisibilityModifierAsString(Field field) {
+ if (Modifier.isPrivate(field.getModifiers()))
+ return "private";
+ else if (Modifier.isProtected(field.getModifiers()))
+ return "protected";
+ else if (Modifier.isPublic(field.getModifiers()))
+ return "public";
+ else
+ return "";
+ }
+}
From b9dbd3452326d9d9b1578aacd4a36519550a8aed Mon Sep 17 00:00:00 2001
From: ghubstan <36207203+ghubstan@users.noreply.github.com>
Date: Thu, 5 Nov 2020 13:16:18 -0300
Subject: [PATCH 3/8] Add gson type adapter for PaymentAccount serialization &
de-serialization
---
.../api/model/PaymentAccountTypeAdapter.java | 323 ++++++++++++++++++
1 file changed, 323 insertions(+)
create mode 100644 core/src/main/java/bisq/core/api/model/PaymentAccountTypeAdapter.java
diff --git a/core/src/main/java/bisq/core/api/model/PaymentAccountTypeAdapter.java b/core/src/main/java/bisq/core/api/model/PaymentAccountTypeAdapter.java
new file mode 100644
index 00000000000..a4265f1bbfe
--- /dev/null
+++ b/core/src/main/java/bisq/core/api/model/PaymentAccountTypeAdapter.java
@@ -0,0 +1,323 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see .
+ */
+
+package bisq.core.api.model;
+
+
+import bisq.core.locale.Country;
+import bisq.core.locale.FiatCurrency;
+import bisq.core.payment.CountryBasedPaymentAccount;
+import bisq.core.payment.PaymentAccount;
+import bisq.core.payment.payload.PaymentAccountPayload;
+
+import com.google.gson.TypeAdapter;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonToken;
+import com.google.gson.stream.JsonWriter;
+
+import java.io.IOException;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Predicate;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import lombok.extern.slf4j.Slf4j;
+
+import static bisq.common.util.ReflectionUtils.getSetterMethodForFieldInClassHierarchy;
+import static bisq.common.util.ReflectionUtils.getVisibilityModifierAsString;
+import static bisq.common.util.ReflectionUtils.isSetterOnClass;
+import static bisq.common.util.ReflectionUtils.loadFieldListForClassHierarchy;
+import static bisq.core.locale.CountryUtil.findCountryByCode;
+import static bisq.core.locale.CurrencyUtil.getCurrencyByCountryCode;
+import static java.lang.String.format;
+import static java.util.Comparator.comparing;
+
+@Slf4j
+class PaymentAccountTypeAdapter extends TypeAdapter {
+
+ private final Class extends PaymentAccount> paymentAccountType;
+ private final Class extends PaymentAccountPayload> paymentAccountPayloadType;
+ private final Map> fieldSettersMap;
+ private final Predicate isExcludedField;
+
+ /**
+ * Constructor used when de-serializing a json payment account from into a
+ * PaymentAccount instance.
+ *
+ * @param paymentAccountType the PaymentAccount subclass being instantiated
+ */
+ public PaymentAccountTypeAdapter(Class extends PaymentAccount> paymentAccountType) {
+ this(paymentAccountType, new String[]{});
+ }
+
+ /**
+ * Constructor used when serializing a PaymentAccount subclass instance into a json
+ * payment account json form.
+ *
+ * @param paymentAccountType the PaymentAccount subclass being serialized
+ * @param excludedFields a string array of field names to exclude from the serialized
+ * payment account json form.
+ */
+ public PaymentAccountTypeAdapter(Class extends PaymentAccount> paymentAccountType, String[] excludedFields) {
+ this.paymentAccountType = paymentAccountType;
+ this.paymentAccountPayloadType = getPaymentAccountPayloadType();
+ this.isExcludedField = (f) -> Arrays.stream(excludedFields).anyMatch(e -> e.equals(f.getName()));
+ this.fieldSettersMap = getFieldSetterMap();
+ }
+
+ @Override
+ public void write(JsonWriter out, PaymentAccount account) throws IOException {
+ // We just write a blank payment acct from for a payment method id.
+ // We're not serializing a real payment account instance here.
+ if (log.isDebugEnabled())
+ log.debug("Writing PaymentAccount json form for fields with accessors...");
+
+ out.beginObject();
+ writeCommonFields(out, account);
+ fieldSettersMap.forEach((field, value) -> {
+ if (log.isDebugEnabled())
+ log.debug("Append form with settable field: {} {} {} setter: {}",
+ getVisibilityModifierAsString(field),
+ field.getType().getSimpleName(),
+ field.getName(),
+ value);
+ try {
+ // Write out a json element if there is a @Setter for this field.
+ if (value.isPresent()) {
+ String fieldName = field.getName();
+ out.name(fieldName);
+ out.value("Your " + fieldName.toLowerCase());
+ }
+ } catch (Exception ex) {
+ throw new IllegalStateException(
+ format("Could not serialize a %s to json", account.getClass().getSimpleName()), ex);
+ }
+ });
+ out.endObject();
+ if (log.isDebugEnabled())
+ log.debug("Done writing PaymentAccount json form.");
+ }
+
+ @Override
+ public PaymentAccount read(JsonReader in) throws IOException {
+ if (log.isDebugEnabled())
+ log.debug("De-serializing json to new {} ...", paymentAccountType.getSimpleName());
+
+ PaymentAccount account = initNewPaymentAccount();
+ in.beginObject();
+ while (in.hasNext()) {
+ String currentFieldName = in.nextName();
+
+ // Some of the fields are common to all payment account types.
+ if (didReadCommonField(in, account, currentFieldName))
+ continue;
+
+ // If the account is a subclass of CountryBasedPaymentAccount, set the
+ // account's Country, and use the Country to derive and set the account's
+ // FiatCurrency.
+ if (didReadCountryField(in, account, currentFieldName))
+ continue;
+
+ try {
+ Optional field = fieldSettersMap.keySet().stream()
+ .filter(k -> k.getName().equals(currentFieldName)).findFirst();
+
+ field.ifPresentOrElse((f) -> invokeSetterMethod(account, f, in), () -> {
+ throw new IllegalStateException(
+ format("Could not de-serialize json to a '%s' because there is no %s field.",
+ account.getClass().getSimpleName(),
+ currentFieldName));
+ });
+ } catch (Exception ex) {
+ throw new IllegalStateException(
+ format("Could not de-serialize json to a '%s'.",
+ account.getClass().getSimpleName()), ex);
+ }
+ }
+ in.endObject();
+ if (log.isDebugEnabled())
+ log.debug("Done de-serializing json.");
+
+ return account;
+ }
+
+ private void invokeSetterMethod(PaymentAccount account, Field field, JsonReader jsonReader) {
+ Optional setter = fieldSettersMap.get(field);
+ if (setter.isPresent()) {
+ try {
+ // The setter might be on the PaymentAccount instance, or its
+ // PaymentAccountPayload instance.
+ if (isSetterOnPaymentAccountClass(setter.get(), account)) {
+ setter.get().invoke(account, nextStringOrNull(jsonReader));
+ } else if (isSetterOnPaymentAccountPayloadClass(setter.get(), account)) {
+ setter.get().invoke(account.getPaymentAccountPayload(), nextStringOrNull(jsonReader));
+ } else {
+ String exMsg = format("Could not de-serialize json to a '%s' using reflection"
+ + " because the setter's declaring class was not found.",
+ account.getClass().getSimpleName());
+ throw new IllegalStateException(exMsg);
+ }
+ } catch (IllegalAccessException | InvocationTargetException ex) {
+ throw new IllegalStateException(
+ format("Could not de-serialize json to a '%s' due to reflection error.",
+ account.getClass().getSimpleName()), ex);
+ }
+ } else {
+ throw new IllegalStateException(
+ format("Could not de-serialize json to a '%s' because there is no setter for field %s.",
+ account.getClass().getSimpleName(),
+ field.getName()));
+ }
+ }
+
+ private boolean isSetterOnPaymentAccountClass(Method setter, PaymentAccount account) {
+ return isSetterOnClass(setter, account.getClass());
+ }
+
+ private boolean isSetterOnPaymentAccountPayloadClass(Method setter, PaymentAccount account) {
+ return isSetterOnClass(setter, account.getPaymentAccountPayload().getClass())
+ || isSetterOnClass(setter, account.getPaymentAccountPayload().getClass().getSuperclass());
+ }
+
+ private Map> getFieldSetterMap() {
+ List orderedFields = getOrderedFields();
+ Map> map = new LinkedHashMap<>();
+ for (Field field : orderedFields) {
+ Optional setter = getSetterMethodForFieldInClassHierarchy(field, paymentAccountType)
+ .or(() -> getSetterMethodForFieldInClassHierarchy(field, paymentAccountPayloadType));
+ map.put(field, setter);
+ }
+ return Collections.unmodifiableMap(map);
+ }
+
+ private List getOrderedFields() {
+ List fields = new ArrayList<>();
+ loadFieldListForClassHierarchy(fields, paymentAccountType, isExcludedField);
+ loadFieldListForClassHierarchy(fields, paymentAccountPayloadType, isExcludedField);
+ fields.sort(comparing(Field::getName));
+ return fields;
+ }
+
+ private String nextStringOrNull(JsonReader in) {
+ try {
+ if (in.peek() == JsonToken.NULL) {
+ in.nextNull();
+ return null;
+ } else {
+ return in.nextString();
+ }
+ } catch (IOException ex) {
+ throw new IllegalStateException("Could not peek at next String value in JsonReader.", ex);
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private Long nextLongOrNull(JsonReader in) {
+ try {
+ if (in.peek() == JsonToken.NULL) {
+ in.nextNull();
+ return null;
+ } else {
+ return in.nextLong();
+ }
+ } catch (IOException ex) {
+ throw new IllegalStateException("Could not peek at next Long value in JsonReader.", ex);
+ }
+ }
+
+ private void writeCommonFields(JsonWriter out, PaymentAccount account) throws IOException {
+ out.name("_COMMENT_");
+ out.value("Please do not edit the paymentMethodId field.");
+
+ out.name("paymentMethodId");
+ out.value(account.getPaymentMethod().getId());
+ }
+
+ private boolean didReadCommonField(JsonReader in, PaymentAccount account, String fieldName) {
+ switch (fieldName) {
+ case "_COMMENT_":
+ case "paymentMethodId":
+ // skip
+ nextStringOrNull(in);
+ return true;
+ case "accountName":
+ account.setAccountName(nextStringOrNull(in));
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private boolean didReadCountryField(JsonReader in, PaymentAccount account, String fieldName) {
+ if (account.isCountryBasedPaymentAccount() && fieldName.equals("country")) {
+ // Read the country code, and use it to set the account's country and single
+ // trade currency fields.
+ String countryCode = nextStringOrNull(in);
+ Optional country = findCountryByCode(countryCode);
+ if (country.isPresent()) {
+ ((CountryBasedPaymentAccount) account).setCountry(country.get());
+ FiatCurrency fiatCurrency = getCurrencyByCountryCode(Objects.requireNonNull(countryCode));
+ account.setSingleTradeCurrency(fiatCurrency);
+ return true;
+ } else {
+ throw new IllegalStateException(
+ format("Could not de-serialize json to a '%s' because %s is an invalid country code.",
+ account.getClass().getSimpleName(), countryCode));
+ }
+ } else {
+ return false;
+ }
+ }
+
+ private Class extends PaymentAccountPayload> getPaymentAccountPayloadType() {
+ try {
+ Package pkg = PaymentAccountPayload.class.getPackage();
+ //noinspection unchecked
+ return (Class extends PaymentAccountPayload>) Class.forName(pkg.getName()
+ + "." + paymentAccountType.getSimpleName() + "Payload");
+ } catch (Exception ex) {
+ throw new IllegalStateException(
+ format("Could not get payload class for %s", paymentAccountType.getSimpleName()), ex);
+ }
+ }
+
+ private PaymentAccount initNewPaymentAccount() {
+ try {
+ Constructor> constructor = paymentAccountType.getDeclaredConstructor();
+ PaymentAccount paymentAccount = (PaymentAccount) constructor.newInstance();
+ paymentAccount.init();
+ return paymentAccount;
+ } catch (NoSuchMethodException ex) {
+ throw new IllegalStateException(format("No default declared constructor found for class %s",
+ paymentAccountType.getSimpleName()), ex);
+ } catch (IllegalAccessException | InstantiationException | InvocationTargetException ex) {
+ throw new IllegalStateException(format("Could not instantiate class %s",
+ paymentAccountType.getSimpleName()), ex);
+ }
+ }
+}
From b84473fbd41172db915cba3ca73e258a3154ba43 Mon Sep 17 00:00:00 2001
From: ghubstan <36207203+ghubstan@users.noreply.github.com>
Date: Thu, 5 Nov 2020 13:17:17 -0300
Subject: [PATCH 4/8] Add PaymentAccountForm for writing empty and submitting
filled fiat acct json forms
---
.../core/api/model/PaymentAccountForm.java | 135 ++++++++++++++++++
1 file changed, 135 insertions(+)
create mode 100644 core/src/main/java/bisq/core/api/model/PaymentAccountForm.java
diff --git a/core/src/main/java/bisq/core/api/model/PaymentAccountForm.java b/core/src/main/java/bisq/core/api/model/PaymentAccountForm.java
new file mode 100644
index 00000000000..7afaf98abdb
--- /dev/null
+++ b/core/src/main/java/bisq/core/api/model/PaymentAccountForm.java
@@ -0,0 +1,135 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see .
+ */
+
+package bisq.core.api.model;
+
+import bisq.core.payment.PaymentAccount;
+import bisq.core.payment.PaymentAccountFactory;
+import bisq.core.payment.payload.PaymentMethod;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+import javax.inject.Singleton;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+
+import java.util.Map;
+
+import java.lang.reflect.Type;
+
+import lombok.extern.slf4j.Slf4j;
+
+import static bisq.core.payment.payload.PaymentMethod.getPaymentMethodById;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static java.io.File.separatorChar;
+import static java.lang.String.format;
+import static java.lang.System.getProperty;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+@Singleton
+@Slf4j
+public class PaymentAccountForm {
+
+ private final GsonBuilder gsonBuilder = new GsonBuilder()
+ .setPrettyPrinting()
+ .serializeNulls();
+
+ // Names of PaymentAccount fields to exclude from json forms.
+ private final String[] excludedFields = new String[]{
+ "log",
+ "id",
+ "acceptedCountryCodes",
+ "countryCode",
+ "creationDate",
+ "excludeFromJsonDataMap",
+ "maxTradePeriod",
+ "paymentAccountPayload",
+ "paymentMethod",
+ "paymentMethodId",
+ "selectedTradeCurrency",
+ "tradeCurrencies",
+ "HOLDER_NAME",
+ "SALT"
+ };
+
+ public File getPaymentAccountForm(String paymentMethodId) {
+ PaymentMethod paymentMethod = getPaymentMethodById(paymentMethodId);
+ File file = new File(getProperty("java.io.tmpdir") + separatorChar
+ + paymentMethod.getId().toLowerCase() + "_form.json");
+ try (OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(file, false), UTF_8)) {
+ PaymentAccount paymentAccount = PaymentAccountFactory.getPaymentAccount(paymentMethod);
+ Class extends PaymentAccount> clazz = paymentAccount.getClass();
+ Gson gson = gsonBuilder.registerTypeAdapter(clazz, new PaymentAccountTypeAdapter(clazz, excludedFields)).create();
+ String json = gson.toJson(paymentAccount); // serializes target to json
+ outputStreamWriter.write(json);
+ } catch (Exception ex) {
+ log.error(format("Could not export json file for %s account.", paymentMethod.getShortName()), ex);
+ }
+ return file;
+ }
+
+ public PaymentAccount toPaymentAccount(File jsonForm) {
+ String json = toJsonString(jsonForm);
+ Class extends PaymentAccount> clazz = getPaymentAccountClassFromJson(json);
+ Gson gson = gsonBuilder.registerTypeAdapter(clazz, new PaymentAccountTypeAdapter(clazz)).create();
+ return gson.fromJson(json, clazz);
+ }
+
+ public String toJsonString(File jsonFile) {
+ try {
+ checkNotNull(jsonFile, "json file cannot be null");
+ return new String(Files.readAllBytes(Paths.get(jsonFile.getAbsolutePath())));
+ } catch (IOException ex) {
+ throw new IllegalStateException(format("Could not read content from file '%s'",
+ jsonFile.getAbsolutePath()), ex);
+ }
+ }
+
+ public URI getClickableURI(File jsonForm) {
+ try {
+ return new URI("file",
+ "",
+ jsonForm.toURI().getPath(),
+ null,
+ null);
+ } catch (URISyntaxException ex) {
+ throw new IllegalArgumentException("", ex);
+ }
+ }
+
+ private Class extends PaymentAccount> getPaymentAccountClassFromJson(String json) {
+ Map jsonMap = gsonBuilder.create().fromJson(json, (Type) Object.class);
+ String paymentMethodId = checkNotNull((String) jsonMap.get("paymentMethodId"),
+ format("Could not find a paymentMethodId in the json string: %s", json));
+ return getPaymentAccountClass(paymentMethodId);
+ }
+
+ private Class extends PaymentAccount> getPaymentAccountClass(String paymentMethodId) {
+ PaymentMethod paymentMethod = PaymentMethod.getPaymentMethodById(paymentMethodId);
+ return PaymentAccountFactory.getPaymentAccount(paymentMethod).getClass();
+ }
+}
From d3be0487a6dd52ea00a1310154906b777a3d3aad Mon Sep 17 00:00:00 2001
From: ghubstan <36207203+ghubstan@users.noreply.github.com>
Date: Thu, 5 Nov 2020 13:19:30 -0300
Subject: [PATCH 5/8] Test PaymentAccount / Json serialization and
de-serialization
---
.../api/model/PaymentAccountFormTest.java | 411 ++++++++++++++++++
1 file changed, 411 insertions(+)
create mode 100644 core/src/test/java/bisq/core/api/model/PaymentAccountFormTest.java
diff --git a/core/src/test/java/bisq/core/api/model/PaymentAccountFormTest.java b/core/src/test/java/bisq/core/api/model/PaymentAccountFormTest.java
new file mode 100644
index 00000000000..ceb5c319f2c
--- /dev/null
+++ b/core/src/test/java/bisq/core/api/model/PaymentAccountFormTest.java
@@ -0,0 +1,411 @@
+/*
+ * This file is part of Bisq.
+ *
+ * Bisq is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * Bisq is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Bisq. If not, see .
+ */
+
+package bisq.core.api.model;
+
+import bisq.core.locale.Res;
+import bisq.core.payment.ChaseQuickPayAccount;
+import bisq.core.payment.ClearXchangeAccount;
+import bisq.core.payment.F2FAccount;
+import bisq.core.payment.HalCashAccount;
+import bisq.core.payment.JapanBankAccount;
+import bisq.core.payment.NationalBankAccount;
+import bisq.core.payment.PaymentAccount;
+import bisq.core.payment.SepaAccount;
+import bisq.core.payment.USPostalMoneyOrderAccount;
+import bisq.core.payment.payload.BankAccountPayload;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.stream.JsonWriter;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+import lombok.extern.slf4j.Slf4j;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static bisq.core.payment.payload.PaymentMethod.*;
+import static java.lang.String.format;
+import static java.lang.System.getProperty;
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+@Slf4j
+public class PaymentAccountFormTest {
+
+ private static final String PROPERTY_NAME_COMMENT = "_COMMENT_";
+ private static final String PROPERTY_VALUE_COMMENT = "Please do not edit the paymentMethodId field.";
+
+ private static final String PROPERTY_NAME_PAYMENT_METHOD_ID = "paymentMethodId";
+
+ private static final String PROPERTY_NAME_ACCOUNT_NAME = "accountName";
+ private static final String PROPERTY_NAME_ACCOUNT_NR = "accountNr";
+ private static final String PROPERTY_NAME_ACCOUNT_TYPE = "accountType";
+ private static final String PROPERTY_NAME_BANK_ACCOUNT_NAME = "bankAccountName";
+ private static final String PROPERTY_NAME_BANK_ACCOUNT_NUMBER = "bankAccountNumber";
+ private static final String PROPERTY_NAME_BANK_ACCOUNT_TYPE = "bankAccountType";
+ private static final String PROPERTY_NAME_BANK_BRANCH_CODE = "bankBranchCode";
+ private static final String PROPERTY_NAME_BANK_BRANCH_NAME = "bankBranchName";
+ private static final String PROPERTY_NAME_BANK_CODE = "bankCode";
+ @SuppressWarnings("unused")
+ private static final String PROPERTY_NAME_BANK_ID = "bankId";
+ private static final String PROPERTY_NAME_BANK_NAME = "bankName";
+ private static final String PROPERTY_NAME_BRANCH_ID = "branchId";
+ private static final String PROPERTY_NAME_BIC = "bic";
+ private static final String PROPERTY_NAME_COUNTRY = "country";
+ private static final String PROPERTY_NAME_CITY = "city";
+ private static final String PROPERTY_NAME_CONTACT = "contact";
+ private static final String PROPERTY_NAME_EMAIL = "email";
+ private static final String PROPERTY_NAME_EMAIL_OR_MOBILE_NR = "emailOrMobileNr";
+ private static final String PROPERTY_NAME_EXTRA_INFO = "extraInfo";
+ private static final String PROPERTY_NAME_HOLDER_NAME = "holderName";
+ private static final String PROPERTY_NAME_HOLDER_TAX_ID = "holderTaxId";
+ private static final String PROPERTY_NAME_IBAN = "iban";
+ private static final String PROPERTY_NAME_MOBILE_NR = "mobileNr";
+ private static final String PROPERTY_NAME_NATIONAL_ACCOUNT_ID = "nationalAccountId";
+ private static final String PROPERTY_NAME_POSTAL_ADDRESS = "postalAddress";
+
+ private static final Gson gson = new GsonBuilder()
+ .setPrettyPrinting()
+ .serializeNulls()
+ .create();
+
+
+ // The payment account serializer / deserializer.
+ private static final PaymentAccountForm paymentAccountForm = new PaymentAccountForm();
+
+ private static final Map EXPECTED_FORM = new HashMap<>();
+
+ @Before
+ public void setup() {
+ Res.setup();
+ EXPECTED_FORM.clear();
+ }
+
+
+ @Test
+ public void testBrazilNationalBankAccountForm() {
+ File emptyForm = paymentAccountForm.getPaymentAccountForm(NATIONAL_BANK_ID);
+ log.info("Empty form saved to {}", paymentAccountForm.getClickableURI(emptyForm));
+ verifyEmptyForm(emptyForm,
+ NATIONAL_BANK_ID,
+ PROPERTY_NAME_ACCOUNT_NR,
+ PROPERTY_NAME_ACCOUNT_TYPE,
+ PROPERTY_NAME_BANK_NAME,
+ PROPERTY_NAME_BRANCH_ID,
+ PROPERTY_NAME_COUNTRY,
+ PROPERTY_NAME_HOLDER_NAME,
+ PROPERTY_NAME_HOLDER_TAX_ID,
+ PROPERTY_NAME_NATIONAL_ACCOUNT_ID);
+
+ EXPECTED_FORM.put(PROPERTY_NAME_PAYMENT_METHOD_ID, NATIONAL_BANK_ID);
+ EXPECTED_FORM.put(PROPERTY_NAME_ACCOUNT_NAME, "Banco do Brasil");
+ EXPECTED_FORM.put(PROPERTY_NAME_ACCOUNT_NR, "456789-87");
+ // No BankId is required for BR.
+ EXPECTED_FORM.put(PROPERTY_NAME_BANK_NAME, "Banco do Brasil");
+ EXPECTED_FORM.put(PROPERTY_NAME_BRANCH_ID, "456789-10");
+ EXPECTED_FORM.put(PROPERTY_NAME_COUNTRY, "BR");
+ EXPECTED_FORM.put(PROPERTY_NAME_HOLDER_NAME, "Joao da Silva");
+ EXPECTED_FORM.put(PROPERTY_NAME_HOLDER_TAX_ID, "123456789");
+ EXPECTED_FORM.put(PROPERTY_NAME_NATIONAL_ACCOUNT_ID, "123456789");
+
+ File completedForm = fillPaymentAccountForm();
+ log.info("Completed form: {}", paymentAccountForm.toJsonString(completedForm));
+
+ NationalBankAccount paymentAccount = (NationalBankAccount) paymentAccountForm.toPaymentAccount(completedForm);
+ verifyAccountFiatCurrency(paymentAccount, "BRL");
+ verifyCommonFormEntries(paymentAccount);
+ assertEquals(EXPECTED_FORM.get(PROPERTY_NAME_COUNTRY),
+ Objects.requireNonNull(paymentAccount.getCountry()).code);
+
+ BankAccountPayload payload = (BankAccountPayload) paymentAccount.getPaymentAccountPayload();
+ assertEquals(EXPECTED_FORM.get(PROPERTY_NAME_ACCOUNT_NR), payload.getAccountNr());
+ // When no BankId is required, getBankId() returns bankName.
+ assertEquals(EXPECTED_FORM.get(PROPERTY_NAME_BANK_NAME), payload.getBankId());
+ assertEquals(EXPECTED_FORM.get(PROPERTY_NAME_BANK_NAME), payload.getBankName());
+ assertEquals(EXPECTED_FORM.get(PROPERTY_NAME_BRANCH_ID), payload.getBranchId());
+ assertEquals(EXPECTED_FORM.get(PROPERTY_NAME_HOLDER_NAME), payload.getHolderName());
+ assertEquals(EXPECTED_FORM.get(PROPERTY_NAME_HOLDER_TAX_ID), payload.getHolderTaxId());
+ assertEquals(EXPECTED_FORM.get(PROPERTY_NAME_NATIONAL_ACCOUNT_ID), payload.getNationalAccountId());
+ // log.info("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount);
+ }
+
+ @Test
+ public void testChaseQuickPayAccountForm() {
+ File emptyForm = paymentAccountForm.getPaymentAccountForm(CHASE_QUICK_PAY_ID);
+ log.info("Empty form saved to {}", paymentAccountForm.getClickableURI(emptyForm));
+ verifyEmptyForm(emptyForm,
+ CHASE_QUICK_PAY_ID,
+ PROPERTY_NAME_EMAIL,
+ PROPERTY_NAME_HOLDER_NAME);
+
+ EXPECTED_FORM.put(PROPERTY_NAME_PAYMENT_METHOD_ID, CHASE_QUICK_PAY_ID);
+ EXPECTED_FORM.put(PROPERTY_NAME_ACCOUNT_NAME, "Quick Pay Acct");
+ EXPECTED_FORM.put(PROPERTY_NAME_EMAIL, "johndoe@quickpay.com");
+ EXPECTED_FORM.put(PROPERTY_NAME_HOLDER_NAME, "John Doe");
+
+ File completedForm = fillPaymentAccountForm();
+ log.info("Completed form: {}", paymentAccountForm.toJsonString(completedForm));
+
+ ChaseQuickPayAccount paymentAccount = (ChaseQuickPayAccount) paymentAccountForm.toPaymentAccount(completedForm);
+ verifyAccountFiatCurrency(paymentAccount, "USD");
+ verifyCommonFormEntries(paymentAccount);
+ assertEquals(EXPECTED_FORM.get(PROPERTY_NAME_EMAIL), paymentAccount.getEmail());
+ assertEquals(EXPECTED_FORM.get(PROPERTY_NAME_HOLDER_NAME), paymentAccount.getHolderName());
+ // log.info("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount);
+ }
+
+ @Test
+ public void testClearXChangeAccountForm() {
+ File emptyForm = paymentAccountForm.getPaymentAccountForm(CLEAR_X_CHANGE_ID);
+ log.info("Empty form saved to {}", paymentAccountForm.getClickableURI(emptyForm));
+ verifyEmptyForm(emptyForm,
+ CLEAR_X_CHANGE_ID,
+ PROPERTY_NAME_EMAIL_OR_MOBILE_NR,
+ PROPERTY_NAME_HOLDER_NAME);
+
+ EXPECTED_FORM.put(PROPERTY_NAME_PAYMENT_METHOD_ID, CLEAR_X_CHANGE_ID);
+ EXPECTED_FORM.put(PROPERTY_NAME_ACCOUNT_NAME, "USD Zelle Account");
+ EXPECTED_FORM.put(PROPERTY_NAME_EMAIL_OR_MOBILE_NR, "jane@doe.com");
+ EXPECTED_FORM.put(PROPERTY_NAME_HOLDER_NAME, "Jane Doe");
+
+ File completedForm = fillPaymentAccountForm();
+ log.info("Completed form: {}", paymentAccountForm.toJsonString(completedForm));
+
+ ClearXchangeAccount paymentAccount = (ClearXchangeAccount) paymentAccountForm.toPaymentAccount(completedForm);
+ verifyCommonFormEntries(paymentAccount);
+ assertEquals(EXPECTED_FORM.get(PROPERTY_NAME_EMAIL_OR_MOBILE_NR), paymentAccount.getEmailOrMobileNr());
+ assertEquals(EXPECTED_FORM.get(PROPERTY_NAME_HOLDER_NAME), paymentAccount.getHolderName());
+ // log.info("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount);
+ verifyAccountFiatCurrency(paymentAccount, "USD");
+ }
+
+ @Test
+ public void testF2FAccountForm() {
+ File emptyForm = paymentAccountForm.getPaymentAccountForm(F2F_ID);
+ log.info("Empty form saved to {}", paymentAccountForm.getClickableURI(emptyForm));
+ verifyEmptyForm(emptyForm,
+ F2F_ID,
+ PROPERTY_NAME_COUNTRY,
+ PROPERTY_NAME_CITY,
+ PROPERTY_NAME_CONTACT,
+ PROPERTY_NAME_EXTRA_INFO);
+
+ EXPECTED_FORM.put(PROPERTY_NAME_PAYMENT_METHOD_ID, F2F_ID);
+ EXPECTED_FORM.put(PROPERTY_NAME_ACCOUNT_NAME, "Conta Cara a Cara");
+ EXPECTED_FORM.put(PROPERTY_NAME_COUNTRY, "BR");
+ EXPECTED_FORM.put(PROPERTY_NAME_CITY, "Rio de Janeiro");
+ EXPECTED_FORM.put(PROPERTY_NAME_CONTACT, "Freddy Beira Mar");
+ EXPECTED_FORM.put(PROPERTY_NAME_EXTRA_INFO, "So fim de semana");
+
+ File completedForm = fillPaymentAccountForm();
+ log.info("Completed form: {}", paymentAccountForm.toJsonString(completedForm));
+
+ F2FAccount paymentAccount = (F2FAccount) paymentAccountForm.toPaymentAccount(completedForm);
+ verifyAccountFiatCurrency(paymentAccount, "BRL");
+ verifyCommonFormEntries(paymentAccount);
+ assertEquals(EXPECTED_FORM.get(PROPERTY_NAME_COUNTRY),
+ Objects.requireNonNull(paymentAccount.getCountry()).code);
+ assertEquals(EXPECTED_FORM.get(PROPERTY_NAME_CITY), paymentAccount.getCity());
+ assertEquals(EXPECTED_FORM.get(PROPERTY_NAME_CONTACT), paymentAccount.getContact());
+ assertEquals(EXPECTED_FORM.get(PROPERTY_NAME_EXTRA_INFO), paymentAccount.getExtraInfo());
+ // log.info("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount);
+ }
+
+ @Test
+ public void testHalCashAccountForm() {
+ File emptyForm = paymentAccountForm.getPaymentAccountForm(HAL_CASH_ID);
+ log.info("Empty form saved to {}", paymentAccountForm.getClickableURI(emptyForm));
+ verifyEmptyForm(emptyForm,
+ HAL_CASH_ID,
+ PROPERTY_NAME_MOBILE_NR);
+
+ EXPECTED_FORM.put(PROPERTY_NAME_PAYMENT_METHOD_ID, HAL_CASH_ID);
+ EXPECTED_FORM.put(PROPERTY_NAME_ACCOUNT_NAME, "Hal Cash Acct");
+ EXPECTED_FORM.put(PROPERTY_NAME_MOBILE_NR, "798 123 456");
+
+ File completedForm = fillPaymentAccountForm();
+ log.info("Completed form: {}", paymentAccountForm.toJsonString(completedForm));
+
+ HalCashAccount paymentAccount = (HalCashAccount) paymentAccountForm.toPaymentAccount(completedForm);
+ verifyAccountFiatCurrency(paymentAccount, "EUR");
+ verifyCommonFormEntries(paymentAccount);
+ assertEquals(EXPECTED_FORM.get(PROPERTY_NAME_MOBILE_NR), paymentAccount.getMobileNr());
+ // log.info("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount);
+ }
+
+ @Test
+ public void testJapanBankAccountForm() {
+ File emptyForm = paymentAccountForm.getPaymentAccountForm(JAPAN_BANK_ID);
+ log.info("Empty form saved to {}", paymentAccountForm.getClickableURI(emptyForm));
+ verifyEmptyForm(emptyForm,
+ JAPAN_BANK_ID,
+ PROPERTY_NAME_BANK_NAME,
+ PROPERTY_NAME_BANK_CODE,
+ PROPERTY_NAME_BANK_BRANCH_CODE,
+ PROPERTY_NAME_BANK_BRANCH_NAME,
+ PROPERTY_NAME_BANK_ACCOUNT_NAME,
+ PROPERTY_NAME_BANK_ACCOUNT_TYPE,
+ PROPERTY_NAME_BANK_ACCOUNT_NUMBER);
+
+ EXPECTED_FORM.put(PROPERTY_NAME_PAYMENT_METHOD_ID, JAPAN_BANK_ID);
+ EXPECTED_FORM.put(PROPERTY_NAME_ACCOUNT_NAME, "Fukuoka Account");
+ EXPECTED_FORM.put(PROPERTY_NAME_BANK_NAME, "Bank of Kyoto");
+ EXPECTED_FORM.put(PROPERTY_NAME_BANK_CODE, "FKBKJPJT");
+ EXPECTED_FORM.put(PROPERTY_NAME_BANK_BRANCH_CODE, "8100-8727");
+ EXPECTED_FORM.put(PROPERTY_NAME_BANK_BRANCH_NAME, "Fukuoka Branch");
+ EXPECTED_FORM.put(PROPERTY_NAME_BANK_ACCOUNT_NAME, "Fukuoka Account");
+ EXPECTED_FORM.put(PROPERTY_NAME_BANK_ACCOUNT_TYPE, "Yen Account");
+ EXPECTED_FORM.put(PROPERTY_NAME_BANK_ACCOUNT_NUMBER, "8100-8727-0000");
+
+ File completedForm = fillPaymentAccountForm();
+ log.info("Completed form: {}", paymentAccountForm.toJsonString(completedForm));
+
+ JapanBankAccount paymentAccount = (JapanBankAccount) paymentAccountForm.toPaymentAccount(completedForm);
+ verifyAccountFiatCurrency(paymentAccount, "JPY");
+ verifyCommonFormEntries(paymentAccount);
+ assertEquals(EXPECTED_FORM.get(PROPERTY_NAME_BANK_CODE), paymentAccount.getBankCode());
+ assertEquals(EXPECTED_FORM.get(PROPERTY_NAME_BANK_NAME), paymentAccount.getBankName());
+ assertEquals(EXPECTED_FORM.get(PROPERTY_NAME_BANK_BRANCH_CODE), paymentAccount.getBankBranchCode());
+ assertEquals(EXPECTED_FORM.get(PROPERTY_NAME_BANK_BRANCH_NAME), paymentAccount.getBankBranchName());
+ assertEquals(EXPECTED_FORM.get(PROPERTY_NAME_BANK_ACCOUNT_NAME), paymentAccount.getBankAccountName());
+ assertEquals(EXPECTED_FORM.get(PROPERTY_NAME_BANK_ACCOUNT_TYPE), paymentAccount.getBankAccountType());
+ assertEquals(EXPECTED_FORM.get(PROPERTY_NAME_BANK_ACCOUNT_NUMBER), paymentAccount.getBankAccountNumber());
+ // log.info("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount);
+ }
+
+
+ @Test
+ public void testSepaAccountForm() {
+ File emptyForm = paymentAccountForm.getPaymentAccountForm(SEPA_ID);
+ log.info("Empty form saved to {}", paymentAccountForm.getClickableURI(emptyForm));
+ verifyEmptyForm(emptyForm,
+ SEPA_ID,
+ PROPERTY_NAME_COUNTRY,
+ PROPERTY_NAME_HOLDER_NAME,
+ PROPERTY_NAME_IBAN,
+ PROPERTY_NAME_BIC);
+
+ EXPECTED_FORM.put(PROPERTY_NAME_PAYMENT_METHOD_ID, SEPA_ID);
+ EXPECTED_FORM.put(PROPERTY_NAME_ACCOUNT_NAME, "Conta Sepa");
+ EXPECTED_FORM.put(PROPERTY_NAME_COUNTRY, "PT");
+ EXPECTED_FORM.put(PROPERTY_NAME_HOLDER_NAME, "Jose da Silva");
+ EXPECTED_FORM.put(PROPERTY_NAME_IBAN, "909-909");
+ EXPECTED_FORM.put(PROPERTY_NAME_BIC, "909");
+
+ File completedForm = fillPaymentAccountForm();
+ log.info("Completed form: {}", paymentAccountForm.toJsonString(completedForm));
+
+ SepaAccount paymentAccount = (SepaAccount) paymentAccountForm.toPaymentAccount(completedForm);
+ assertEquals(EXPECTED_FORM.get(PROPERTY_NAME_COUNTRY), Objects.requireNonNull(paymentAccount.getCountry()).code);
+ verifyAccountFiatCurrency(paymentAccount, "EUR");
+ verifyCommonFormEntries(paymentAccount);
+ assertEquals(EXPECTED_FORM.get(PROPERTY_NAME_HOLDER_NAME), paymentAccount.getHolderName());
+ assertEquals(EXPECTED_FORM.get(PROPERTY_NAME_IBAN), paymentAccount.getIban());
+ assertEquals(EXPECTED_FORM.get(PROPERTY_NAME_BIC), paymentAccount.getBic());
+ // bankId == bic
+ assertEquals(EXPECTED_FORM.get(PROPERTY_NAME_BIC), paymentAccount.getBankId());
+ // log.info("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount);
+ }
+
+ @Test
+ public void testUSPostalMoneyOrderAccountForm() {
+ File emptyForm = paymentAccountForm.getPaymentAccountForm(US_POSTAL_MONEY_ORDER_ID);
+ log.info("Empty form saved to {}", paymentAccountForm.getClickableURI(emptyForm));
+ verifyEmptyForm(emptyForm,
+ US_POSTAL_MONEY_ORDER_ID,
+ PROPERTY_NAME_HOLDER_NAME,
+ PROPERTY_NAME_POSTAL_ADDRESS);
+
+ EXPECTED_FORM.put(PROPERTY_NAME_PAYMENT_METHOD_ID, US_POSTAL_MONEY_ORDER_ID);
+ EXPECTED_FORM.put(PROPERTY_NAME_ACCOUNT_NAME, "Bubba's Acct");
+ EXPECTED_FORM.put(PROPERTY_NAME_HOLDER_NAME, "Bubba");
+ EXPECTED_FORM.put(PROPERTY_NAME_POSTAL_ADDRESS, "100 Westwood Terrace Austin, TX 78701");
+
+ File completedForm = fillPaymentAccountForm();
+ log.info("Completed form: {}", paymentAccountForm.toJsonString(completedForm));
+
+ USPostalMoneyOrderAccount paymentAccount = (USPostalMoneyOrderAccount) paymentAccountForm.toPaymentAccount(completedForm);
+ verifyAccountFiatCurrency(paymentAccount, "USD");
+ verifyCommonFormEntries(paymentAccount);
+ assertEquals(EXPECTED_FORM.get(PROPERTY_NAME_HOLDER_NAME), paymentAccount.getHolderName());
+ assertEquals(EXPECTED_FORM.get(PROPERTY_NAME_POSTAL_ADDRESS), paymentAccount.getPostalAddress());
+ // log.info("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount);
+ }
+
+
+ // Private
+
+ private void verifyCommonFormEntries(PaymentAccount paymentAccount) {
+ assertNotNull(paymentAccount);
+ assertEquals(EXPECTED_FORM.get(PROPERTY_NAME_PAYMENT_METHOD_ID), paymentAccount.getPaymentMethod().getId());
+ assertTrue(paymentAccount.getCreationDate().getTime() > 0);
+ assertEquals(EXPECTED_FORM.get(PROPERTY_NAME_ACCOUNT_NAME), paymentAccount.getAccountName());
+ }
+
+ private void verifyEmptyForm(File jsonForm, String paymentMethodId, String... fields) {
+ @SuppressWarnings("unchecked")
+ Map emptyForm = (Map) gson.fromJson(
+ paymentAccountForm.toJsonString(jsonForm),
+ Object.class);
+ assertNotNull(emptyForm);
+ assertEquals(PROPERTY_VALUE_COMMENT, emptyForm.get(PROPERTY_NAME_COMMENT));
+ assertEquals(paymentMethodId, emptyForm.get(PROPERTY_NAME_PAYMENT_METHOD_ID));
+ assertEquals("Your accountname", emptyForm.get(PROPERTY_NAME_ACCOUNT_NAME));
+ for (String field : fields) {
+ assertEquals("Your " + field.toLowerCase(), emptyForm.get(field));
+ }
+ }
+
+ private void verifyAccountFiatCurrency(PaymentAccount paymentAccount, String expectedCurrencyCode) {
+ assertEquals(expectedCurrencyCode, Objects.requireNonNull(paymentAccount.getSingleTradeCurrency()).getCode());
+ }
+
+ private File fillPaymentAccountForm() {
+ File f = new File(getProperty("java.io.tmpdir"), "tmp.json");
+ try {
+ JsonWriter writer = new JsonWriter(new OutputStreamWriter(new FileOutputStream(f), UTF_8));
+ writer.beginObject();
+ writer.name(PROPERTY_NAME_COMMENT);
+ writer.value(PROPERTY_VALUE_COMMENT);
+ for (Map.Entry entry : EXPECTED_FORM.entrySet()) {
+ String k = entry.getKey();
+ Object v = entry.getValue();
+ writer.name(k);
+ writer.value(v.toString());
+ }
+ writer.endObject();
+ writer.close();
+ } catch (IOException ex) {
+ log.error("", ex);
+ fail(format("Could not write json file from form entries %s", EXPECTED_FORM));
+ }
+ return f;
+ }
+}
From 61827afe49d1be6be5434399d3d68e708e84e087 Mon Sep 17 00:00:00 2001
From: ghubstan <36207203+ghubstan@users.noreply.github.com>
Date: Thu, 5 Nov 2020 13:47:27 -0300
Subject: [PATCH 6/8] Fix import problem
---
.../src/main/java/bisq/core/api/model/PaymentAccountForm.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/core/src/main/java/bisq/core/api/model/PaymentAccountForm.java b/core/src/main/java/bisq/core/api/model/PaymentAccountForm.java
index 7afaf98abdb..836abd4e59e 100644
--- a/core/src/main/java/bisq/core/api/model/PaymentAccountForm.java
+++ b/core/src/main/java/bisq/core/api/model/PaymentAccountForm.java
@@ -43,7 +43,7 @@
import lombok.extern.slf4j.Slf4j;
-import static bisq.core.payment.payload.PaymentMethod.getPaymentMethodById;
+import static bisq.core.payment.payload.PaymentMethod.*;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.io.File.separatorChar;
import static java.lang.String.format;
@@ -129,7 +129,7 @@ private Class extends PaymentAccount> getPaymentAccountClassFromJson(String js
}
private Class extends PaymentAccount> getPaymentAccountClass(String paymentMethodId) {
- PaymentMethod paymentMethod = PaymentMethod.getPaymentMethodById(paymentMethodId);
+ PaymentMethod paymentMethod = getPaymentMethodById(paymentMethodId);
return PaymentAccountFactory.getPaymentAccount(paymentMethod).getClass();
}
}
From a2f8f1efe31995c2c53968e560e65c7b68d53545 Mon Sep 17 00:00:00 2001
From: ghubstan <36207203+ghubstan@users.noreply.github.com>
Date: Thu, 5 Nov 2020 18:13:12 -0300
Subject: [PATCH 7/8] Remove extra white spaces, force travis ci builds
---
.../test/java/bisq/core/api/model/PaymentAccountFormTest.java | 3 ---
1 file changed, 3 deletions(-)
diff --git a/core/src/test/java/bisq/core/api/model/PaymentAccountFormTest.java b/core/src/test/java/bisq/core/api/model/PaymentAccountFormTest.java
index ceb5c319f2c..f315870fa72 100644
--- a/core/src/test/java/bisq/core/api/model/PaymentAccountFormTest.java
+++ b/core/src/test/java/bisq/core/api/model/PaymentAccountFormTest.java
@@ -108,7 +108,6 @@ public void setup() {
EXPECTED_FORM.clear();
}
-
@Test
public void testBrazilNationalBankAccountForm() {
File emptyForm = paymentAccountForm.getPaymentAccountForm(NATIONAL_BANK_ID);
@@ -300,7 +299,6 @@ public void testJapanBankAccountForm() {
// log.info("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount);
}
-
@Test
public void testSepaAccountForm() {
File emptyForm = paymentAccountForm.getPaymentAccountForm(SEPA_ID);
@@ -359,7 +357,6 @@ public void testUSPostalMoneyOrderAccountForm() {
// log.info("Deserialized {}: {}", paymentAccount.getClass().getSimpleName(), paymentAccount);
}
-
// Private
private void verifyCommonFormEntries(PaymentAccount paymentAccount) {
From 190656643b516440964737a1b343504359ecbafc Mon Sep 17 00:00:00 2001
From: ghubstan <36207203+ghubstan@users.noreply.github.com>
Date: Fri, 6 Nov 2020 13:07:08 -0300
Subject: [PATCH 8/8] Give all files created in tmp dirs a unique name
Delete tmp files upon test jvm exit.
---
.../core/api/model/PaymentAccountForm.java | 18 ++++++++++++-----
.../api/model/PaymentAccountFormTest.java | 20 ++++++++++++++++---
2 files changed, 30 insertions(+), 8 deletions(-)
diff --git a/core/src/main/java/bisq/core/api/model/PaymentAccountForm.java b/core/src/main/java/bisq/core/api/model/PaymentAccountForm.java
index 836abd4e59e..268d5ab9083 100644
--- a/core/src/main/java/bisq/core/api/model/PaymentAccountForm.java
+++ b/core/src/main/java/bisq/core/api/model/PaymentAccountForm.java
@@ -43,9 +43,8 @@
import lombok.extern.slf4j.Slf4j;
-import static bisq.core.payment.payload.PaymentMethod.*;
+import static bisq.core.payment.payload.PaymentMethod.getPaymentMethodById;
import static com.google.common.base.Preconditions.checkNotNull;
-import static java.io.File.separatorChar;
import static java.lang.String.format;
import static java.lang.System.getProperty;
import static java.nio.charset.StandardCharsets.UTF_8;
@@ -78,9 +77,17 @@ public class PaymentAccountForm {
public File getPaymentAccountForm(String paymentMethodId) {
PaymentMethod paymentMethod = getPaymentMethodById(paymentMethodId);
- File file = new File(getProperty("java.io.tmpdir") + separatorChar
- + paymentMethod.getId().toLowerCase() + "_form.json");
- try (OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(file, false), UTF_8)) {
+
+ File file = null;
+ try {
+ file = File.createTempFile(paymentMethod.getId().toLowerCase() + "_form_",
+ ".json",
+ Paths.get(getProperty("java.io.tmpdir")).toFile());
+ } catch (IOException ex) {
+ log.error("", ex);
+ }
+
+ try (OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(checkNotNull(file), false), UTF_8)) {
PaymentAccount paymentAccount = PaymentAccountFactory.getPaymentAccount(paymentMethod);
Class extends PaymentAccount> clazz = paymentAccount.getClass();
Gson gson = gsonBuilder.registerTypeAdapter(clazz, new PaymentAccountTypeAdapter(clazz, excludedFields)).create();
@@ -89,6 +96,7 @@ public File getPaymentAccountForm(String paymentMethodId) {
} catch (Exception ex) {
log.error(format("Could not export json file for %s account.", paymentMethod.getShortName()), ex);
}
+
return file;
}
diff --git a/core/src/test/java/bisq/core/api/model/PaymentAccountFormTest.java b/core/src/test/java/bisq/core/api/model/PaymentAccountFormTest.java
index f315870fa72..611e366a477 100644
--- a/core/src/test/java/bisq/core/api/model/PaymentAccountFormTest.java
+++ b/core/src/test/java/bisq/core/api/model/PaymentAccountFormTest.java
@@ -33,6 +33,8 @@
import com.google.gson.GsonBuilder;
import com.google.gson.stream.JsonWriter;
+import java.nio.file.Paths;
+
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -111,6 +113,7 @@ public void setup() {
@Test
public void testBrazilNationalBankAccountForm() {
File emptyForm = paymentAccountForm.getPaymentAccountForm(NATIONAL_BANK_ID);
+ emptyForm.deleteOnExit();
log.info("Empty form saved to {}", paymentAccountForm.getClickableURI(emptyForm));
verifyEmptyForm(emptyForm,
NATIONAL_BANK_ID,
@@ -158,6 +161,7 @@ public void testBrazilNationalBankAccountForm() {
@Test
public void testChaseQuickPayAccountForm() {
File emptyForm = paymentAccountForm.getPaymentAccountForm(CHASE_QUICK_PAY_ID);
+ emptyForm.deleteOnExit();
log.info("Empty form saved to {}", paymentAccountForm.getClickableURI(emptyForm));
verifyEmptyForm(emptyForm,
CHASE_QUICK_PAY_ID,
@@ -183,6 +187,7 @@ public void testChaseQuickPayAccountForm() {
@Test
public void testClearXChangeAccountForm() {
File emptyForm = paymentAccountForm.getPaymentAccountForm(CLEAR_X_CHANGE_ID);
+ emptyForm.deleteOnExit();
log.info("Empty form saved to {}", paymentAccountForm.getClickableURI(emptyForm));
verifyEmptyForm(emptyForm,
CLEAR_X_CHANGE_ID,
@@ -208,6 +213,7 @@ public void testClearXChangeAccountForm() {
@Test
public void testF2FAccountForm() {
File emptyForm = paymentAccountForm.getPaymentAccountForm(F2F_ID);
+ emptyForm.deleteOnExit();
log.info("Empty form saved to {}", paymentAccountForm.getClickableURI(emptyForm));
verifyEmptyForm(emptyForm,
F2F_ID,
@@ -240,6 +246,7 @@ public void testF2FAccountForm() {
@Test
public void testHalCashAccountForm() {
File emptyForm = paymentAccountForm.getPaymentAccountForm(HAL_CASH_ID);
+ emptyForm.deleteOnExit();
log.info("Empty form saved to {}", paymentAccountForm.getClickableURI(emptyForm));
verifyEmptyForm(emptyForm,
HAL_CASH_ID,
@@ -262,6 +269,7 @@ public void testHalCashAccountForm() {
@Test
public void testJapanBankAccountForm() {
File emptyForm = paymentAccountForm.getPaymentAccountForm(JAPAN_BANK_ID);
+ emptyForm.deleteOnExit();
log.info("Empty form saved to {}", paymentAccountForm.getClickableURI(emptyForm));
verifyEmptyForm(emptyForm,
JAPAN_BANK_ID,
@@ -302,6 +310,7 @@ public void testJapanBankAccountForm() {
@Test
public void testSepaAccountForm() {
File emptyForm = paymentAccountForm.getPaymentAccountForm(SEPA_ID);
+ emptyForm.deleteOnExit();
log.info("Empty form saved to {}", paymentAccountForm.getClickableURI(emptyForm));
verifyEmptyForm(emptyForm,
SEPA_ID,
@@ -335,6 +344,7 @@ public void testSepaAccountForm() {
@Test
public void testUSPostalMoneyOrderAccountForm() {
File emptyForm = paymentAccountForm.getPaymentAccountForm(US_POSTAL_MONEY_ORDER_ID);
+ emptyForm.deleteOnExit();
log.info("Empty form saved to {}", paymentAccountForm.getClickableURI(emptyForm));
verifyEmptyForm(emptyForm,
US_POSTAL_MONEY_ORDER_ID,
@@ -385,9 +395,13 @@ private void verifyAccountFiatCurrency(PaymentAccount paymentAccount, String exp
}
private File fillPaymentAccountForm() {
- File f = new File(getProperty("java.io.tmpdir"), "tmp.json");
+ File tmpJsonForm = null;
try {
- JsonWriter writer = new JsonWriter(new OutputStreamWriter(new FileOutputStream(f), UTF_8));
+ tmpJsonForm = File.createTempFile("temp_acct_form_",
+ ".json",
+ Paths.get(getProperty("java.io.tmpdir")).toFile());
+ tmpJsonForm.deleteOnExit();
+ JsonWriter writer = new JsonWriter(new OutputStreamWriter(new FileOutputStream(tmpJsonForm), UTF_8));
writer.beginObject();
writer.name(PROPERTY_NAME_COMMENT);
writer.value(PROPERTY_VALUE_COMMENT);
@@ -403,6 +417,6 @@ private File fillPaymentAccountForm() {
log.error("", ex);
fail(format("Could not write json file from form entries %s", EXPECTED_FORM));
}
- return f;
+ return tmpJsonForm;
}
}