dotnet / MQTTnet

MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker). The implementation is based on the documentation from http://mqtt.org/.
MIT License
4.48k stars 1.07k forks source link

ClassNotFoundException: Didn't find class "java.util.Optional" #571

Closed bangonkali closed 5 years ago

bangonkali commented 5 years ago

Some background info. We're looking in to moving from a legacy Xamarin Android + MQTTNet to hopefully a Flutter based implementation with native Kotlin service bindings. The App is designed to act as a short term server for embedded devices. Same strategy has worked with Xamarin Android + MQTTNet only the next version is planned to be implemented using Flutter.

Expected behavior

Server runs

Actual behavior

Problem areas are calls to Optional class. This feels like I just missed something very basic. Only the calls to Optional.xxx() is causing the issue, as in the case below.

/io/moquette/broker/NewNettyAcceptor.class

        boolean useFineMetrics = props.boolProp("use_metrics", false);
        if (useFineMetrics) {
            DropWizardMetricsHandler metricsHandler = new DropWizardMetricsHandler();
            metricsHandler.init(props);
            this.metrics = Optional.of(metricsHandler);
        } else {
            this.metrics = Optional.empty();
        }
 Caused by: java.lang.ClassNotFoundException: Didn't find class "java.util.Optional" on path: DexPathList[[zip file "/data/app/com.company.myapp-2/base.apk"],nativeLibraryDirectories=[/data/app/com.company.myapp-2/lib/arm, /data/app/com.company.myapp-2/base.apk!/lib/armeabi-v7a, /vendor/lib, /system/lib]]

Full Error

03-11 06:18:49.873 8832-8832/com.company.myapp.service.process E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.company.myapp.service.process, PID: 8832
    java.lang.NoClassDefFoundError: Failed resolution of: Ljava/util/Optional;
        at io.moquette.broker.NewNettyAcceptor.initialize(NewNettyAcceptor.java:140)
        at io.moquette.broker.Server.startServer(Server.java:190)
        at io.moquette.broker.Server.startServer(Server.java:135)
        at io.moquette.broker.Server.startServer(Server.java:122)
        at com.company.myapp.moquette.MoquetteBroker.start(MoquetteBroker.kt:60)
        at com.company.myapp.MyAppService.startMoquette(MyAppService.kt:30)
        at com.company.myapp.MyAppService.onStartCommand(MyAppService.kt:56)
        at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3010)
        at android.app.ActivityThread.-wrap17(ActivityThread.java)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1442)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:148)
        at android.app.ActivityThread.main(ActivityThread.java:5417)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
     Caused by: java.lang.ClassNotFoundException: Didn't find class "java.util.Optional" on path: DexPathList[[zip file "/data/app/com.company.myapp-2/base.apk"],nativeLibraryDirectories=[/data/app/com.company.myapp-2/lib/arm, /data/app/com.company.myapp-2/base.apk!/lib/armeabi-v7a, /vendor/lib, /system/lib]]
        at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
        at io.moquette.broker.NewNettyAcceptor.initialize(NewNettyAcceptor.java:140) 
        at io.moquette.broker.Server.startServer(Server.java:190) 
        at io.moquette.broker.Server.startServer(Server.java:135) 
        at io.moquette.broker.Server.startServer(Server.java:122) 
        at com.company.myapp.moquette.MoquetteBroker.start(MoquetteBroker.kt:60) 
        at com.company.myapp.MyAppService.startMoquette(MyAppService.kt:30) 
        at com.company.myapp.MyAppService.onStartCommand(MyAppService.kt:56) 
        at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3010) 
        at android.app.ActivityThread.-wrap17(ActivityThread.java) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1442) 
        at android.os.Handler.dispatchMessage(Handler.java:102) 
        at android.os.Looper.loop(Looper.java:148) 
        at android.app.ActivityThread.main(ActivityThread.java:5417) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 
        Suppressed: java.lang.ClassNotFoundException: java.util.Optional
        at java.lang.Class.classForName(Native Method)
        at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
        at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
                ... 17 more
     Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack trace available

Steps to reproduce

Minimal yet complete reproducer code (or URL to code) or complete log file

Can't produce this now as there is a lot of proprietary code. Working on a redacted code.

Moquette MQTT version

implementation 'io.moquette:moquette-broker:0.12'

JVM version (e.g. java -version)

def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
    localPropertiesFile.withReader('UTF-8') { reader ->
        localProperties.load(reader)
    }
}

def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
    throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}

def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
    flutterVersionCode = '1'
}

def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
    flutterVersionName = '1.0'
}

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"

android {
    compileSdkVersion 28

    sourceSets {
        main.java.srcDirs += 'src/main/kotlin'
    }

    lintOptions {
        disable 'InvalidPackage'
    }

    defaultConfig {
        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
        applicationId "com.company.myapp"
        minSdkVersion 21
        targetSdkVersion 28
        multiDexEnabled true
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            // TODO: Add your own signing config for the release build.
            // Signing with the debug keys for now, so `flutter run --release` works.
            signingConfig signingConfigs.debug
        }
    }

    packagingOptions {
        exclude 'META-INF/DEPENDENCIES'
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/LICENSE.txt'
        exclude 'META-INF/license.txt'
        exclude 'META-INF/NOTICE'
        exclude 'META-INF/NOTICE.txt'
        exclude 'META-INF/notice.txt'
        exclude 'META-INF/ASL2.0'
        exclude 'META-INF/INDEX.LIST'
        exclude 'META-INF/io.netty.versions.properties'
    }
}

flutter {
    source '../..'
}

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.0.2'
    implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.0.2'
    implementation 'io.moquette:moquette-broker:0.12'
}

configurations.all {
    resolutionStrategy.eachDependency { DependencyResolveDetails details ->
        def requested = details.requested
        if (requested.group == "com.android.support") {
            if (!requested.name.startsWith("multidex")) {
                details.useVersion "27.+"
            }
        }
    }
}

OS version (e.g. uname -a)

Android

bangonkali commented 5 years ago

Seems like the cause could be https://developer.android.com/reference/java/util/Optional not being supported on API level 23 which is the Device I'm currently testing with. Will update as soon as I test with a more recent device.

bangonkali commented 5 years ago

I can now confirm this is indeed an issue with API level 23 and below. It works perfectly well with Android API level 24 and above.