androiddb4o

db4o on Android 4.4.+: storing an object fails because cannot cast long to integer


While running db4o library (Both 8.1-SNAPSHOT and 8.0), opening the database works

oc = Db4oEmbedded.openFile(dbConfig(), db4oDBFullPath(context)); //context.getDir("data", 0) + "/" + "mDB.DB4O"; to get the full path

However, once I start trying to store an object

oc.store(object)

I get the error, cannot cast java.lang.Long to java.lang.Integer. This problem is caused probably by the new dalvik implementation for the new Android OS versions, but is there any patches or workarounds for this error available?

A guy was introducing a patch here but it's inaccessible.

Full stacktrace of the error

java.lang.UnsupportedOperationException: java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.Integer at com.db4o.internal.DalvikVM$Dalvik3ObjectFactoryFactory.(DalvikVM.java:120) at com.db4o.internal.DalvikVM.factory(DalvikVM.java:75) at com.db4o.internal.DalvikVM.supportSkipConstructorCall(DalvikVM.java:55) at com.db4o.internal.Platform4.callConstructor(Platform4.java:463) at com.db4o.reflect.core.ConstructorSupport.createConstructor(ConstructorSupport.java:21) at com.db4o.reflect.jdk.JdkClass.constructorSpec(JdkClass.java:176) at com.db4o.reflect.jdk.JdkClass.ensureCanBeInstantiated(JdkClass.java:182) at com.db4o.reflect.generic.GenericClass.ensureCanBeInstantiated(GenericClass.java:282) at com.db4o.internal.ClassMetadata.createConstructor(ClassMetadata.java:684) at com.db4o.internal.ClassMetadata.initializeConstructor(ClassMetadata.java:648) at com.db4o.internal.ClassMetadata.initializeAspects(ClassMetadata.java:266) at com.db4o.internal.ClassMetadata.checkChanges(ClassMetadata.java:494) at com.db4o.internal.ClassMetadataRepository.readClassMetadata(ClassMetadataRepository.java:465) at com.db4o.internal.ClassMetadataRepository.classMetadataForId(ClassMetadataRepository.java:259) at com.db4o.internal.ObjectContainerBase.classMetadataForID(ObjectContainerBase.java:1069) at com.db4o.internal.marshall.ObjectHeader.(ObjectHeader.java:39) at com.db4o.internal.marshall.ObjectHeader.(ObjectHeader.java:23) at com.db4o.internal.marshall.UnmarshallingContext.readObjectHeader(UnmarshallingContext.java:124) at com.db4o.internal.marshall.UnmarshallingContext.read(UnmarshallingContext.java:47) at com.db4o.internal.ObjectReference.read(ObjectReference.java:306) at com.db4o.internal.ObjectReference.read(ObjectReference.java:292) at com.db4o.internal.ObjectContainerBase.getByID2(ObjectContainerBase.java:886) at com.db4o.internal.ObjectContainerBase.getByID(ObjectContainerBase.java:857) at com.db4o.internal.fileheader.FileHeaderVariablePart.readIdentity(FileHeaderVariablePart.java:44) at com.db4o.internal.fileheader.NewFileHeaderBase.readIdentity(NewFileHeaderBase.java:92) at com.db4o.internal.LocalObjectContainer.readThis(LocalObjectContainer.java:497) at com.db4o.internal.IoAdaptedObjectContainer.openImpl(IoAdaptedObjectContainer.java:71) at com.db4o.internal.ObjectContainerBase$1.run(ObjectContainerBase.java:140) at com.db4o.foundation.DynamicVariable.with(DynamicVariable.java:54) at com.db4o.foundation.Environments.runWith(Environments.java:28) at com.db4o.internal.ObjectContainerBase.withEnvironment(ObjectContainerBase.java:161) at com.db4o.internal.ObjectContainerBase.open(ObjectContainerBase.java:131) at com.db4o.internal.IoAdaptedObjectContainer.(IoAdaptedObjectContainer.java:35) at com.db4o.internal.ObjectContainerFactory.openObjectContainer(ObjectContainerFactory.java:18) at com.db4o.Db4oEmbedded.openFile(Db4oEmbedded.java:64)

Update:

So, after tracing the error, it turns out that there is a terrible cast from Long to Integer inside com.db4o.internal.DalvikVM in version 8.0

int _methodId; _methodId = (Integer) constructorIdMethod.invoke(null, Object.class);

I tried to fix this by declaring the variable as long. I recompiled and ran again on Android, I got another error which is UnsupportedOperationException: java.lang.NoSuchMethodException: newInstance [class java.lang.Class, int]

Caused by this:

        try {
            _method = ObjectStreamClass.class.getDeclaredMethod("newInstance", Class.class, Integer.TYPE); 
            _method.setAccessible(true);
        } catch (Exception e) {
            throw new UnsupportedOperationException(e);
        } 
    }

Any clue how to solve this?


Solution

  • I managed to fix this by creating a patch in the code of db4o 8.1

    Here you go, the new JAR file and code changes are available in this GITHUB repository. There is also a demo for testing the library on the repo.

    I changed few lines in com.db4o.internal.Platform4. Basically I changed the order of JDKs to look up.

    private static void createJdk() {
    
    
        Class<?>[] jdkFactories = {
    
                JDK_5.Factory.class,//1 switched both positions.
                DalvikVM.Factory.class,//2
                JDK_1_4.Factory.class,
                JDK_1_3.Factory.class,
                JDK_1_2.Factory.class,
                JDKReflect.Factory.class,
        };
        //-----