Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Stackoverflow on RealmAny toString #7479

Open
wants to merge 3 commits into
base: releases
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
## 10.6.1 (YYYY-MM-DD)

### Enhancements
* None.

### Fixed
* `StackOverflow` when calling `toString()` on a `DynamicRealmObject` containing a cyclic reference through a `RealmAny` field.

### Compatibility
* File format: Generates Realms with format v22. Unsynced Realms will be upgraded from Realm Java 2.0 and later. Synced Realms can only be read and upgraded if created with Realm Java v10.0.0-BETA.1.
* APIs are backwards compatible with all previous release of realm-java in the 10.6.y series.
* Realm Studio 11.0.0-alpha.0 or above is required to open Realms created by this version.

### Internal
* None.


## 10.6.0 (2021-06-15)

This release combines all changes from 10.6.0-BETA.1 and 10.6.0-BETA.2.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -354,4 +354,29 @@ class DynamicRealmAnyTests {
assertEquals(0, realmAnyList.size)
}
}

@Test
fun toString_test() {
realm.executeTransaction { transactionRealm ->
val anObject = transactionRealm.createObject("RealmAnyObject")

mapOf(
RealmAny.valueOf(10.toInt()) to "RealmAny<Integer>(10)",
RealmAny.valueOf(true) to "RealmAny<Boolean>(true)",
RealmAny.valueOf("Hello world") to "RealmAny<String>(Hello world)",
RealmAny.valueOf(byteArrayOf(0, 1)) to "RealmAny<byte[]>([0, 1])",
RealmAny.valueOf(Date(100)) to "RealmAny<Date>(Thu Jan 01 01:00:00 GMT+01:00 1970)",
RealmAny.valueOf(10.0.toFloat()) to "RealmAny<Float>(10.0)",
RealmAny.valueOf(10.0.toDouble()) to "RealmAny<Double>(10.0)",
RealmAny.valueOf(Decimal128(100)) to "RealmAny<Decimal128>(100)",
RealmAny.valueOf(ObjectId(TestHelper.generateObjectIdHexString(0))) to "RealmAny<ObjectId>(0123456789abcdef01234567)",
RealmAny.valueOf(anObject) to "RealmAny<RealmAnyObject>(id:0)",
RealmAny.valueOf(UUID.fromString("00000000-0000-0000-0000-000000000000")) to "RealmAny<UUID>(00000000-0000-0000-0000-000000000000)",
RealmAny.nullValue() to "RealmAny<Null>"
).map {
anObject.setRealmAny("myRealmAny", it.key)
assertEquals("RealmAnyObject = dynamic[{myRealmAny:${it.value}}]", anObject.toString())
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1760,7 +1760,48 @@ public String toString() {
sb.append(proxyState.getRow$realm().isNull(columnKey) ? "null" : proxyState.getRow$realm().getUUID(columnKey));
break;
case MIXED:
sb.append(proxyState.getRow$realm().isNull(columnKey) ? "null" : getRealmAny(columnKey));
RealmAny realmAny = getRealmAny(columnKey);
switch (realmAny.getType()){
case INTEGER:
sb.append(String.format(Locale.US, "RealmAny<%s>(%s)", "Integer", realmAny.asInteger().toString()));
break;
case BOOLEAN:
sb.append(String.format(Locale.US, "RealmAny<%s>(%s)", "Boolean", realmAny.asBoolean().toString()));
break;
case STRING:
sb.append(String.format(Locale.US, "RealmAny<%s>(%s)", "String", realmAny.asString()));
break;
case BINARY:
sb.append(String.format(Locale.US, "RealmAny<%s>(%s)", "byte[]", Arrays.toString(realmAny.asBinary())));
break;
case DATE:
sb.append(String.format(Locale.US, "RealmAny<%s>(%s)", "Date", realmAny.asDate().toString()));
break;
case FLOAT:
sb.append(String.format(Locale.US, "RealmAny<%s>(%s)", "Float", realmAny.asFloat().toString()));
break;
case DOUBLE:
sb.append(String.format(Locale.US, "RealmAny<%s>(%s)", "Double", realmAny.asDouble().toString()));
break;
case DECIMAL128:
sb.append(String.format(Locale.US, "RealmAny<%s>(%s)", "Decimal128", realmAny.asDecimal128().toString()));
break;
case OBJECT_ID:
sb.append(String.format(Locale.US, "RealmAny<%s>(%s)", "ObjectId", realmAny.asObjectId().toString()));
break;
case OBJECT:
// if a Realm object, don't print the contents as it might end in a cycle.
String tableName = realmAny.asRealmModel(DynamicRealmObject.class).proxyState.getRow$realm().getTable().getClassName();
long objectKey = realmAny.asRealmModel(DynamicRealmObject.class).proxyState.getRow$realm().getObjectKey();
sb.append(String.format(Locale.US, "RealmAny<%s>(objKey:%d)", tableName, objectKey));
break;
case UUID:
sb.append(String.format(Locale.US, "RealmAny<%s>(%s)", "UUID", realmAny.asUUID().toString()));
break;
case NULL:
sb.append("RealmAny<Null>");
break;
}
break;
case OBJECT:
sb.append(proxyState.getRow$realm().isNullLink(columnKey)
Expand Down
10 changes: 10 additions & 0 deletions realm/realm-library/src/main/java/io/realm/RealmAny.java
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,16 @@ public static RealmAny valueOf(@Nullable RealmModel value) {
return new RealmAny((value == null) ? new NullRealmAnyOperator() : new RealmModelOperator(value));
}

/**
* Creates a new RealmAny with the specified value.
*
* @param value the RealmAny value.
* @return a new RealmAny of a DynamicRealmObject.
*/
public static RealmAny valueOf(@Nullable DynamicRealmObject value) {
return new RealmAny((value == null) ? new NullRealmAnyOperator() : new DynamicRealmModelRealmAnyOperator(value));
}

/**
* Returns true if the inner value is null, false otherwise.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,10 @@ private static <T extends RealmModel> T getRealmModel(BaseRealm realm, NativeRea
return realm.get((Class<T>) DynamicRealmObject.class, className, nativeRealmAny.getRealmModelRowKey());
}

DynamicRealmModelRealmAnyOperator(RealmModel realmModel) {
super(realmModel);
}

DynamicRealmModelRealmAnyOperator(BaseRealm realm, NativeRealmAny nativeRealmAny) {
super(getRealmModel(realm, nativeRealmAny));
}
Expand Down
2 changes: 1 addition & 1 deletion version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
10.6.0
10.6.1-SNAPSHOT