Fixed
Status Update
Comments
yb...@google.com <yb...@google.com> #2
I should probably elaborate on that a bit more here :P. The ideal case would be that data classes written in other modules work the same when consumed. A standard data class (no secondary constructors, `val` properties) works fine when in the same module. The errors produced are also pretty confusing. They'll usually give what they read from the bytecode (constructor params called "var0" or the like) and reports missing setters for fields without names of said fields.
yb...@google.com <yb...@google.com> #3
I can confirm the bug and the workaround. The same problem arises when you use a data-class from a library with @Embedded
yb...@google.com <yb...@google.com> #5
given that log, looks like kotlin again not generating proper parameter names for methods.
yb...@google.com <yb...@google.com>
mm...@commonsware.com <mm...@commonsware.com> #6
so turns out this is not about kotlin.
does not work w/ javac either because parameter names are not part of the class signature unless compiled w/ debug.
We will need to add a new annotation to support this.
does not work w/ javac either because parameter names are not part of the class signature unless compiled w/ debug.
We will need to add a new annotation to support this.
yb...@google.com <yb...@google.com> #7
True on the javac bit, but for kotlin you should be able to read the parameter names from the `@Metadata` annotations (since the param names are part of the public API in kotlin). There's no public API around this today though admittedly :/
yb...@google.com <yb...@google.com> #8
actually i have a CL that makes this work for java as well but may not work for release builds (didn't try)
but it is shady, uses private APi and someday will break.
on the other hand, kotlin version seems to make sense, I'll ask kotlin folks to see if they have any plans to open it up.
but it is shady, uses private APi and someday will break.
on the other hand, kotlin version seems to make sense, I'll ask kotlin folks to see if they have any plans to open it up.
Description
Version used: 1.0.0-beta1
Devices/Android versions reproduced on: n/a
This work got lost when that issue was marked as fixed.
We really need SupportSQLiteQuery to expose a getArgCount() (or the equivalent). In principle, we need the arguments themselves to be exposed, but so far we have been getting away without those.
Quoting myself from the above comment:
"The docs for rawQueryWithFactory() on SQLiteDatabase say the following for the selectionArgs parameter: "You may include ?s in where clause in the query, which will be replaced by the values from selectionArgs. The values will be bound as Strings."
"The FrameworkSQLiteDatabase implementation passes an empty String[] to rawQueryWithFactory()... then assumes that it can actually bind selection arguments later, despite saying (via the empty String[]) that there aren't any selection arguments.
"Perhaps that works with the native SQLiteDatabase, but it would appear that SQLCipher for Android assumes that the code calling rawQueryWithFactory() isn't lying about the selection arguments. Hence, we need those arguments (or perhaps just the count) before calling rawQueryWithFactory() on SQLCipher's SQLiteDatabase, but mBindArgs is private in SimpleSQLiteQuery, and in some cases, we are not the ones creating the SimpleSQLiteQuery instance (so we can't fork SimpleSQLiteQuery and provide our own implementation)."
So, for example, lacking a getArgCount(), we have to use reflection to try to get that value from some stock SupportSQLiteQuery implementations:
@Override
public Cursor query(final SupportSQLiteQuery supportQuery,
CancellationSignal signal) {
int count=0;
try {
if (supportQuery instanceof RoomSQLiteQuery) {
Field argCount = RoomSQLiteQuery.class.getDeclaredField("mArgCount");
argCount.setAccessible(true);
count = argCount.getInt(supportQuery);
}
else if (supportQuery instanceof SimpleSQLiteQuery) {
Field bindArgs = SimpleSQLiteQuery.class.getDeclaredField("mBindArgs");
bindArgs.setAccessible(true);
Object[] bindArgsValue = (Object[]) bindArgs.get(supportQuery);
count = bindArgsValue!=null?bindArgsValue.length:0;
}
else {
throw new IllegalArgumentException("Unexpected SupportSQLiteQuery type: "
+supportQuery.getClass().getCanonicalName());
}
}
catch (Exception e) {
throw new IllegalStateException("Um, ick", e);
}
String[] fakeArgs=new String[count];
for (int i=0;i<count;i++) {
fakeArgs[i]="";
}
return(safeDb.rawQueryWithFactory(
new net.sqlcipher.database.SQLiteDatabase.CursorFactory() {
@Override
public net.sqlcipher.Cursor newCursor(
net.sqlcipher.database.SQLiteDatabase db,
SQLiteCursorDriver masterQuery, String editTable,
SQLiteQuery query) {
supportQuery.bindTo(new Program(query));
return new SQLiteCursor(db, masterQuery, editTable, query);
}
}, supportQuery.getSql(), fakeArgs, null));
}
Adding getArgCount() would eliminate the reflection. We still wind up lying to SQLCipher for Android (and possibly other SQLite implementations) about the arguments, so it'll still be ugly, just less ugly.