Search code examples
androidgroovyjavacv

Groovy for Android with JavaCV results in NoClassDefFoundError


I'm using JavaCV in an Android project to manipulate some images. I successfully created the plain Java project with the native libraries for JavaCV and the app works fine. Then I wanted to try to port the project to Groovy for Android:

java.lang.NoClassDefFoundError: java/awt/image/BufferedImage at java.lang.Class.getDeclaredMethods(Native Method) at java.lang.Class.getDeclaredMethods(Class.java:703) at org.codehaus.groovy.reflection.stdclasses.CachedSAMClass$1.run(CachedSAMClass.java:100) at org.codehaus.groovy.reflection.stdclasses.CachedSAMClass$1.run(CachedSAMClass.java:98) at java.security.AccessController.doPrivileged(AccessController.java:45) at org.codehaus.groovy.reflection.stdclasses.CachedSAMClass.getDeclaredMethods(CachedSAMClass.java:98) at org.codehaus.groovy.reflection.stdclasses.CachedSAMClass.getAbstractMethods(CachedSAMClass.java:116) at org.codehaus.groovy.reflection.stdclasses.CachedSAMClass.getSAMMethod(CachedSAMClass.java:182) at org.codehaus.groovy.reflection.ClassInfo.isSAM(ClassInfo.java:344) at org.codehaus.groovy.reflection.ClassInfo.createCachedClass(ClassInfo.java:334) at org.codehaus.groovy.reflection.ClassInfo.access$700(ClassInfo.java:38) at org.codehaus.groovy.reflection.ClassInfo$LazyCachedClassRef.initValue(ClassInfo.java:482) at org.codehaus.groovy.reflection.ClassInfo$LazyCachedClassRef.initValue(ClassInfo.java:473) at org.codehaus.groovy.util.LazyReference.getLocked(LazyReference.java:46) at org.codehaus.groovy.util.LazyReference.get(LazyReference.java:33) at org.codehaus.groovy.reflection.ClassInfo.getCachedClass(ClassInfo.java:108) at org.codehaus.groovy.reflection.ReflectionCache.getCachedClass(ReflectionCache.java:107) at org.codehaus.groovy.reflection.CachedClass$4.initValue(CachedClass.java:136) at org.codehaus.groovy.reflection.CachedClass$4.initValue(CachedClass.java:133) at org.codehaus.groovy.util.LazyReference.getLocked(LazyReference.java:46) at org.codehaus.groovy.util.LazyReference.get(LazyReference.java:33) at org.codehaus.groovy.reflection.CachedClass.getCachedSuperClass(CachedClass.java:243) at org.codehaus.groovy.reflection.CachedClass$8.initValue(CachedClass.java:209) at org.codehaus.groovy.reflection.CachedClass$8.initValue(CachedClass.java:195) at org.codehaus.groovy.util.LazyReference.getLocked(LazyReference.java:46) at org.codehaus.groovy.util.LazyReference.get(LazyReference.java:33) at org.codehaus.groovy.reflection.CachedClass.getInterfaces(CachedClass.java:247) at org.codehaus.groovy.reflection.CachedClass.(CachedClass.java:233) at org.codehaus.groovy.reflection.ClassInfo.createCachedClass(ClassInfo.java:337) at org.codehaus.groovy.reflection.ClassInfo.access$700(ClassInfo.java:38) at org.codehaus.groovy.reflection.ClassInfo$LazyCachedClassRef.initValue(ClassInfo.java:482) at org.codehaus.groovy.reflection.ClassInfo$LazyCachedClassRef.initValue(ClassInfo.java:473) at org.codehaus.groovy.util.LazyReference.getLocked(LazyReference.java:46) at org.codehaus.groovy.util.LazyReference.get(LazyReference.java:33) at org.codehaus.groovy.reflection.ClassInfo.getCachedClass(ClassInfo.java:108) at org.codehaus.groovy.reflection.ReflectionCache.getCachedClass(ReflectionCache.java:107) at org.codehaus.groovy.reflection.ParameterTypes.getParametersTypes0(ParameterTypes.java:78) at org.codehaus.groovy.reflection.ParameterTypes.getParameterTypes(ParameterTypes.java:64) at org.codehaus.groovy.reflection.CachedMethod.compareToCachedMethod(CachedMethod.java:154) at org.codehaus.groovy.reflection.CachedMethod.compareTo(CachedMethod.java:137) at java.util.ComparableTimSort.binarySort(ComparableTimSort.java:228) at java.util.ComparableTimSort.sort(ComparableTimSort.java:172) at java.util.ComparableTimSort.sort(ComparableTimSort.java:142) at java.util.Arrays.sort(Arrays.java:1973) at org.codehaus.groovy.reflection.CachedClass$3.initValue(CachedClass.java:117) at org.codehaus.groovy.reflection.CachedClass$3.initValue(CachedClass.java:79) at org.codehaus.groovy.util.LazyReference.getLocked(LazyReference.java:46) at org.codehaus.groovy.util.LazyReference.get(LazyReference.java:33) at org.codehaus.groovy.reflection.CachedClass.getMethods(CachedClass.java:255) at groovy.lang.MetaClassImpl.populateMet

Here's the code snippet using Javacv:

            FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outFile, width, height);
            recorder.setVideoCodec(avcodec.AV_CODEC_ID_MPEG4);
            recorder.setFormat("mp4");
            recorder.setFrameRate(frameRate);
            recorder.setVideoQuality(videoQuality);
            /* some non Javacv stuff */
                    while(!finished)
                    {
                            opencv_core.IplImage image = cvLoadImage(picPath);
                            recorder.record(image);
                            opencv_core.cvReleaseImage(image);
                    }

I know Android does not ship with AWT, but as far as the plain Java project goes, this is not an issue. I have this problem only when using Groovy. I just spent the whole morning trying to figure this out with no luck, also tried passing the resulting debug apk through Proguard but it only made more confusion. Any ideas how to solve this?


Solution

  • So, I'm answering my question by myself. It took me a few days to figure this out: I had to add @CompileStatic annotation to all the methods using the native libraries.

    It's worth noting that it is recommended (again: https://speakerdeck.com/glaforge/groovy-on-android-droidcon-paris-2014) to add @CompileStatic as much as possible, for performance reasons.