diff --git a/src/main/java/org/stellar/sdk/Memo.java b/src/main/java/org/stellar/sdk/Memo.java
index b0a5f9f35..a4aeab1c1 100644
--- a/src/main/java/org/stellar/sdk/Memo.java
+++ b/src/main/java/org/stellar/sdk/Memo.java
@@ -2,6 +2,8 @@
import com.google.common.io.BaseEncoding;
+import java.nio.charset.Charset;
+
/**
*
The memo contains optional extra information. It is the responsibility of the client to interpret this value. Memos can be one of the following types:
*
@@ -24,10 +26,18 @@ public static MemoNone none() {
/**
* Creates new {@link MemoText} instance.
- * @param text
+ * @param text text in utf8 encoding
*/
public static MemoText text(String text) {
- return new MemoText(text);
+ return new MemoText(text, Charset.forName("UTF8"));
+ }
+
+ /**
+ * Creates new {@link MemoText} instance.
+ * @param text text in unknown encoding
+ */
+ public static MemoText textUnknownEncoding(String text) {
+ return new MemoText(text,null);
}
/**
diff --git a/src/main/java/org/stellar/sdk/MemoText.java b/src/main/java/org/stellar/sdk/MemoText.java
index 0dcb4b2c3..276b712b7 100644
--- a/src/main/java/org/stellar/sdk/MemoText.java
+++ b/src/main/java/org/stellar/sdk/MemoText.java
@@ -3,6 +3,7 @@
import com.google.common.base.Objects;
import org.stellar.sdk.xdr.MemoType;
+import javax.annotation.Nullable;
import java.nio.charset.Charset;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -13,12 +14,19 @@
public class MemoText extends Memo {
private String text;
- public MemoText(String text) {
+ public MemoText(String text, @Nullable Charset encoding) {
this.text = checkNotNull(text, "text cannot be null");
- int length = text.getBytes((Charset.forName("UTF-8"))).length;
+ int length;
+ if (encoding != null) {
+ length = text.getBytes(encoding).length;
+ } else {
+ int lengthUtf8 = text.getBytes((Charset.forName("UTF-8"))).length;
+ int lengthAscii = text.getBytes((Charset.forName("ASCII"))).length;
+ length = Math.min(lengthUtf8, lengthAscii);
+ }
if (length > 28) {
- throw new MemoTooLongException("text must be <= 28 bytes. length=" + String.valueOf(length));
+ throw new MemoTooLongException("text must be <= 28 bytes. length=" + length);
}
}
diff --git a/src/main/java/org/stellar/sdk/responses/TransactionDeserializer.java b/src/main/java/org/stellar/sdk/responses/TransactionDeserializer.java
index 098f07e65..2ff4ea497 100644
--- a/src/main/java/org/stellar/sdk/responses/TransactionDeserializer.java
+++ b/src/main/java/org/stellar/sdk/responses/TransactionDeserializer.java
@@ -33,7 +33,7 @@ public TransactionResponse deserialize(JsonElement json, Type typeOfT, JsonDeser
if (memoType.equals("text")) {
JsonElement memoField = json.getAsJsonObject().get("memo");
if (memoField != null) {
- memo = Memo.text(memoField.getAsString());
+ memo = Memo.textUnknownEncoding(memoField.getAsString());
} else {
memo = Memo.text("");
}
diff --git a/src/test/java/org/stellar/sdk/MemoTest.java b/src/test/java/org/stellar/sdk/MemoTest.java
index 850749ed8..a591fe353 100644
--- a/src/test/java/org/stellar/sdk/MemoTest.java
+++ b/src/test/java/org/stellar/sdk/MemoTest.java
@@ -9,6 +9,7 @@
import org.stellar.sdk.responses.TransactionDeserializer;
import org.stellar.sdk.responses.TransactionResponse;
+import java.nio.charset.Charset;
import java.util.Arrays;
import static org.junit.Assert.*;
@@ -50,7 +51,7 @@ public void testMemoTextTooLong() {
@Test
public void testMemoTextTooLongUtf8() {
try {
- Memo.text("价值交易的开源协议!!");
+ new MemoText("价值交易的开源协议!!", Charset.forName("UTF8"));
fail();
} catch (RuntimeException exception) {
assertTrue(exception.getMessage().contains("text must be <= 28 bytes."));
@@ -136,4 +137,29 @@ public void testMemoReturnHashSuccess() {
assertEquals("4142434445464748494a4b4c0000000000000000000000000000000000000000", BaseEncoding.base16().lowerCase().encode(memoXdr.getRetHash().getHash()));
assertEquals("4142434445464748494a4b4c", memo.getTrimmedHexValue());
}
+
+ @Test
+ public void testMemoTextAscii() {
+ String asciiStr = "\u0223\u0025\ufffd\u0060\ufffd\ufffd\ufffd\u006d\u005a\u0041\u0076\u000e\ufffd\ufffd\u0002\u0049\u0004\ufffd\ufffd\ufffd\ufffd\ufffd\u0062\ufffd\u0031\ufffd\u0010";
+ try {
+ Memo.text(asciiStr);
+ fail(); // More then 28 bytes in UTF8 encoding
+ } catch (MemoTooLongException e) {
+ }
+ MemoText memo = Memo.textUnknownEncoding(asciiStr);
+ assertEquals(asciiStr, memo.getText());
+ assertEquals(asciiStr, memo.toString());
+ }
+
+ @Test
+ public void testMemoTextAsciiTooLong() {
+ String longStr = "\u0223\u0025\ufffd\u0060\ufffd\ufffd\ufffd\u006d\u005a\u0041\u0076\u000e\ufffd\ufffd\u0002\u0049\u0004\ufffd\ufffd\ufffd\ufffd\ufffd\u0062\ufffd\u0031\ufffd\u0010\u0028\u0029";
+
+ try {
+ Memo.textUnknownEncoding(longStr);
+ fail();
+ } catch (MemoTooLongException exception) {
+ assertTrue(exception.getMessage().contains("text must be <= 28 bytes."));
+ }
+ }
}