MyObject не может быть сохранен в массиве типа MyObject[]
Я получил следующий отчет о сбое
java.lang.ArrayStoreException: de.benibela.videlibri.jni.Bridge$Account cannot be stored in an array of type de.benibela.videlibri.jni.Bridge$Account[] at de.benibela.videlibri.jni.Bridge.VLGetAccounts(Native Method) at de.benibela.videlibri.Accounts.refreshAll(Accounts.kt:61) at de.benibela.videlibri.VideLibriApp$Companion.initializeAll(VideLibriApp.kt:305) at de.benibela.videlibri.VideLibriApp.onCreate(VideLibriApp.kt:49) at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1020) at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5009)
с телефона Samsung SM-G900F Android 5.0.
Эта ошибка не невозможна?
У меня есть этот код Java
package de.benibela.videlibri.jni;
public class Bridge {
//...
public static class Account implements Serializable{
@NotNull public String libId, name, pass, prettyName;
public int type;
public boolean extend;
public int extendDays;
public boolean history;
public int lastCheckDate;
public Account () {
libId = name = pass = prettyName = "";
}
public Account (@NotNull String libId, @NotNull String name, @NotNull String pass, @NotNull String prettyName,
int type, boolean extend,
int extendDays, boolean history,
int lastCheckDate) {
this.libId = libId;
this.name = name;
this.pass = pass;
this.prettyName = prettyName;
this.type = type;
this.extend = extend;
this.extendDays = extendDays;
this.history = history;
this.lastCheckDate = lastCheckDate;
}
//...
и этот код на Паскале для взаимодействия с ним:
//global variables
var accountClass: jobject;
accountClassInitWithData: jmethodID;
accounts: TAccountList;
//...
with j do begin
accountClass := newGlobalRefAndDelete(getclass('de/benibela/videlibri/jni/Bridge$Account'));
accountClassInitWithData := getmethod(accountClass, '<init>', '(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IZIZI)V');
end;
function accountToJAccount(account: TCustomAccountAccess): jobject;
var args: array[0..8] of jvalue;
i: Integer;
begin
with j do begin
args[0].l := stringToJString(account.getLibrary().id);
args[1].l := stringToJString(account.getUser());
args[2].l := stringToJString(account.passWord);
args[3].l := stringToJString(account.prettyName);
args[4].i := account.accountType;
args[5].z := booleanToJboolean(account.extendType <> etNever);
args[6].i := account.extendDays;
args[7].z := booleanToJboolean(account.keepHistory);
args[8].i := account.lastCheckDate;
result := newObject(accountClass, accountClassInitWithData, @args[0]);
for i := 0 to 3 do deleteLocalRef(args[i].l);
end;
end;
function Java_de_benibela_VideLibri_Bridge_VLGetAccounts(env:PJNIEnv; this:jobject): jobject; cdecl;
var
i: Integer;
begin
if logging then bbdebugtools.log('de.benibela.VideLibri.Bride.VLGetAccounts (started)');
try
result := j.newObjectArray(accounts.Count, accountClass, nil);
with j do
for i := 0 to accounts.Count - 1 do
setObjectArrayElementAndDelete(result, i, accountToJAccount(accounts[i]));
except
on e: Exception do throwExceptionToJava(e);
end;
if logging then bbdebugtools.log('de.benibela.VideLibri.Bride.VLGetAccounts (ended)');
end;
j
это просто оболочка вокруг указателя JNI env:
type TJavaEnv = record
env: PJNIEnv;
//...
end;
threadvar j: TJavaEnv; //JNI helper object
function TJavaEnv.newObject(c: jclass; m: jmethodID; args: Pjvalue): jobject;
begin
result := env^^.NewObjectA(env, c, m, args);
end;
function TJavaEnv.newObjectArray(len: integer; c: jclass; def: jobject): jobject;
begin
result := env^^.NewObjectArray(env, len, c, def);
end;
function TJavaEnv.newGlobalRefAndDelete(obj: jobject): jobject;
begin
result := env^^.NewGlobalRef(env, obj);
deleteLocalRef(obj);
end;
function TJavaEnv.getclass(n: pchar): jclass;
var
jn: jobject;
begin
if jCustomClassLoader <> nil then begin
jn := stringToJString(n);
result := callObjectMethod(jCustomClassLoader, jCustomClassLoaderFindClassMethod, @jn);
if ExceptionCheck then begin
env^^.ExceptionClear(env);
result := nil;
end;
deleteLocalRef(jn);
if result <> nil then exit;
end;
result := env^^.FindClass(env, n);
checkResult(result, 'class', n, '');
end;
function TJavaEnv.getmethod(c: jclass; n, sig: pchar): jmethodID;
begin
result := env^^.GetMethodID(env, c, n, sig);
checkResult(result, 'method', n, '');
end;
function TJavaEnv.ExceptionCheck: boolean;
begin
result := env^^.ExceptionCheck(env) <> JNI_FALSE
end;
function TJavaEnv.callObjectMethod(obj: jobject; methodID: jmethodID; args: Pjvalue): jobject;
begin
result := env^^.CallObjectMethodA(env, obj, methodID, args);
end;
procedure TJavaEnv.setObjectArrayElement(a: jobject; index: integer; v: jobject);
begin
env^^.SetObjectArrayElement(env, a, index, v);
end;
procedure TJavaEnv.setObjectArrayElementAndDelete(a: jobject; index: integer; v: jobject);
begin
setObjectArrayElement(a, index, v);
deleteLocalRef(v);
end;
procedure TJavaEnv.deleteLocalRef(obj: jobject);
begin
env^^.DeleteLocalRef(env, obj);
end;
function TJavaEnv.NewStringUTF(s: string): jobject; inline;
begin
result := env^^.NewStringUTF(env, pchar(s));
end;
function TJavaEnv.stringToJString(s: string; conversionMode: TStringConversionMode = scmConvertAndRepairUTF8ToMUTF8): jobject;
var ok: integer;
begin
if (conversionMode = scmAssumeMUTF8) then
exit(NewStringUTF(s));
ok := isValidModifiedUTF8(s, conversionMode);
if ok = 0 then
exit(NewStringUTF(s));
if (ok = INVALID_UTF8) and (conversionMode = scmConvertValidUTF8ToMUTF8) then
raise EAndroidInterfaceException.create('String is invalid utf-8: '+strFromPtr(pointer(s))+':'+inttostr(length(s)));
exit(NewStringUTF(repairModifiedUTF8(s)));
end;
function TJavaEnv.booleanToJboolean(b: boolean): jboolean;
begin
if b then result := JNI_TRUE
else result := JNI_FALSE;
end;
procedure setCustomClassLoaderFromLoadedClass(c: jclass);
var classClass, classLoaderClass: jclass;
getClassLoaderMethod: jmethodID;
begin
//see https://stackru.com/questions/13263340/findclass-from-any-thread-in-android-jni
with needJ do begin
classClass := env^^.GetObjectClass(env, c);
getClassLoaderMethod := getmethod(classClass, 'getClassLoader', '()Ljava/lang/ClassLoader;');
jCustomClassLoader := newGlobalRefAndDelete(callObjectMethodChecked(c, getClassLoaderMethod));
classLoaderClass := env^^.FindClass(env, 'java/lang/ClassLoader');
jCustomClassLoaderFindClassMethod := getmethod(classLoaderClass, 'findClass', '(Ljava/lang/String;)Ljava/lang/Class;');
end;
end;
//in JNI_OnLoad
setCustomClassLoaderFromLoadedClass(j.env^^.FindClass(j.env, 'de/benibela/videlibri/jni/Bridge'));