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'));

0 ответов

Другие вопросы по тегам