#StackBounty: #unit-testing #spring #kotlin #junit Are these Unit tests OK or am I implementing an antipattern or not following best pr…

Bounty: 50

I am testing a Spring boot service using JUnit 5 and Mockito. I haven’t spent much time on unit testing in the past so I’m not sure if I’m accidentally implementing an anti-pattern or not following best practices.

I read multiple times that it’s good practice to have one assertion per test, I have one assertion but I also have a few verify assertions that check if the method I’m testing called the correct methods with the correct input based on the conditional branch I’m testing as well as the input to the method I’m testing, is this OK/acceptable or should I split it up into one assertion/verify assertion per test? It feels like that would require a lot of code duplication… Below are four tests I wrote and the method I’m testing. For clarity I’ll also add the code that sets up and handles my test application context.

Any ideas/advice would be much appreciated.

The method I am testing:

@Transactional
    override fun startSession(msisdn: String, origConnID: String, configSetName: String): StartSessionResponseDTO {
        val txId = generateTxID()
        val ss = sessionStatus(msisdn)

        eventService.logEvent(EventType.StartSessionRequest, txId, msisdn, hashMapOf("extTxId" to origConnID))

        if (ss == null) {
            throw ApplicationException(type = ApplicationException.Type.client_error, message = "Concurrent Access Detected: ${msisdn}")
        } else {
            if (ss.sessionId == null || ss.ip == null) {
                //create new Nuance session
                nuanceService.startSession(NuanceStartSessionReqDto(txId, msisdn, configSetName = configSetName)).let {
                    updateSession(msisdn = msisdn, sessionId = it.sessionId, ip = it.ip, origConnID = origConnID)
                }
            } else {
                //check if the sessionId is still valid
                if (!nuanceService.isSessionValid(txId = txId, msisdn = msisdn, sessionId = ss.sessionId, host = ss.ip, configSetName = configSetName)) {
                    nuanceService.startSession(NuanceStartSessionReqDto(txId, msisdn, configSetName = configSetName)).let {
                        updateSession(msisdn = msisdn, sessionId = it.sessionId, ip = it.ip, origConnID = origConnID)
                    }
                }
            }
        }

        eventService.logEvent(type = EventType.StartSessionResponse, txId = txId, msisdn = msisdn)
        return StartSessionResponseDTO(msisdn)
    }

My test class:

@ExtendWith(SpringExtension::class)
@ContextConfiguration()
class  VBServiceTests() {

    @TestConfiguration
    class testConfig {
        @Bean
        fun jdbcTemplate(): NamedParameterJdbcTemplate {
            return mock<NamedParameterJdbcTemplate>()
        }

        @Bean
        fun nuanceService(): NuanceService {
            return mock<NuanceService>()
        }

        @Bean
        fun appConfigProps(): AppConfigProps {
            return mock<AppConfigProps>()
        }

        @Bean
        fun eventService(): EventServiceImp {
            return mock<EventServiceImp>()
        }

        @Bean
        fun audioTrimService(): AudioTrimService {
            return mock<AudioTrimService>()
        }

        @Bean
        fun vbNuanceStagingDeletionService(): VbNuanceStagingDeletionsService {
            return mock<VbNuanceStagingDeletionsService>()
        }
    }

    @MockBean
    lateinit var nuanceService: NuanceService

    @MockBean
    lateinit var eventService: EventServiceImp

    @SpyBean
    lateinit var vbServiceSpy: VbServiceImp

    val msisdn = "0821234567"
    val origConnID = "o123"
    val sessionId = "0821234567"
    val ip = "127.0.0.1"
    val txId = "1234-5678"
    val configSetName = "LoIvrPhraIvrHdr"

    @Test
    fun `startSession | When method is called with valid input a StartSessionDTO is returned, if no Nuance session exists a new Nuance session will be created and persisted`() {
        doNothing().whenever(vbServiceSpy).updateSession(msisdn, origConnID, sessionId, ip)
        doReturn(txId).whenever(vbServiceSpy).generateTxID()
        doReturn(SessionStatus(msisdn, origConnID, null, null)).whenever(vbServiceSpy).sessionStatus(msisdn)

        given(nuanceService.startSession(NuanceStartSessionReqDto(txId, msisdn, configSetName = configSetName))).willReturn(NuanceStartSessionRespDto(txId, sessionId, ip))

        assertThat(vbServiceSpy.startSession(msisdn, origConnID, configSetName), Is(StartSessionResponseDTO(msisdn)))
        verify(vbServiceSpy).generateTxID()
        verify(vbServiceSpy).sessionStatus(msisdn)
        verify(eventService).logEvent(StartSessionRequest, txId, msisdn, hashMapOf("extTxId" to origConnID))
        verify(nuanceService).startSession(NuanceStartSessionReqDto(txId, msisdn, configSetName = configSetName))
        verify(vbServiceSpy).updateSession(msisdn = msisdn, sessionId = sessionId, ip = ip, origConnID = origConnID)
        verify(eventService).logEvent(type = EventType.StartSessionResponse, txId = txId, msisdn = msisdn)
    }

    @Test
    fun `startSession | When method is called with valid input a StartSessionDTO is returned, if existing valid Nuance session exists the existing session will be used`() {
        doNothing().whenever(vbServiceSpy).updateSession(msisdn, origConnID, sessionId, ip)
        doReturn(txId).whenever(vbServiceSpy).generateTxID()
        doReturn(SessionStatus(msisdn, origConnID, sessionId, ip)).whenever(vbServiceSpy).sessionStatus(msisdn)

        given(nuanceService.isSessionValid(txId, msisdn, sessionId, ip, configSetName)).willReturn(true)

        assertThat(vbServiceSpy.startSession(msisdn, origConnID, configSetName), Is(StartSessionResponseDTO(msisdn)))
        verify(vbServiceSpy).generateTxID()
        verify(vbServiceSpy).sessionStatus(msisdn)
        verify(eventService).logEvent(StartSessionRequest, txId, msisdn, hashMapOf("extTxId" to origConnID))
        verify(eventService).logEvent(type = EventType.StartSessionResponse, txId = txId, msisdn = msisdn)
    }

    @Test
    fun `startSession | When method is called with valid input a StartSessionDTO is returned, if existing invalid Nuance session exists a new session will be created and the existing session record will be updated`() {
        doNothing().whenever(vbServiceSpy).updateSession(msisdn, origConnID, sessionId, ip)
        doReturn(txId).whenever(vbServiceSpy).generateTxID()
        doReturn(SessionStatus(msisdn, origConnID, sessionId, ip)).whenever(vbServiceSpy).sessionStatus(msisdn)

        given(nuanceService.isSessionValid(txId, msisdn, sessionId, ip, configSetName)).willReturn(false)
        given(nuanceService.startSession(NuanceStartSessionReqDto(txId, msisdn, configSetName = configSetName))).willReturn(NuanceStartSessionRespDto(txId, sessionId, ip))

        assertThat(vbServiceSpy.startSession(msisdn, origConnID, configSetName), Is(StartSessionResponseDTO(msisdn)))
        verify(vbServiceSpy).generateTxID()
        verify(vbServiceSpy).sessionStatus(msisdn)
        verify(eventService).logEvent(StartSessionRequest, txId, msisdn, hashMapOf("extTxId" to origConnID))
        verify(nuanceService).startSession(NuanceStartSessionReqDto(txId, msisdn, configSetName = configSetName))
        verify(vbServiceSpy).updateSession(msisdn = msisdn, sessionId = sessionId, ip = ip, origConnID = origConnID)
        verify(eventService).logEvent(type = EventType.StartSessionResponse, txId = txId, msisdn = msisdn)
    }

    @Test()
    fun `startSession - When method is called with valid input when sessionStatus returns null concurrent access is detected and an ApplicationException gets thrown`() {
        doReturn(txId).whenever(vbServiceSpy).generateTxID()
        doReturn(null).whenever(vbServiceSpy).sessionStatus(msisdn)

        val exception = Assertions.assertThrows(ApplicationException::class.java) {
            vbServiceSpy.startSession(msisdn, origConnID, configSetName)
        }

        assertThat(exception.message, Is("Concurrent Access Detected: ${msisdn}"))


        verify(vbServiceSpy).generateTxID()
        verify(vbServiceSpy).sessionStatus(msisdn)
    }


}


Get this bounty!!!

#StackBounty: #kotlin #gradle #protocol-buffers #grpc #micronaut Very simple grpc/proto endpoint implementation causing java.lang.NoSuc…

Bounty: 50

The closest issue I found is this one and basically it says: "… you use the version of kotlin-stdlib on the runtime classpath not lower than the one on the compile classpath… "

As far as I can see I am right with kotlin versions.

My whole project is quite small and can be downloaded from github

build.gradle

plugins {
    id("org.jetbrains.kotlin.jvm") version "1.4.10"
    id("org.jetbrains.kotlin.kapt") version "1.4.10"
    id("org.jetbrains.kotlin.plugin.allopen") version "1.4.10"
    id("com.github.johnrengelman.shadow") version "6.1.0"
    id("io.micronaut.application") version "1.2.0"
    id("com.google.protobuf") version "0.8.13"
}

version = "0.1"
group = "com.tolearn"

repositories {
    mavenCentral()
    jcenter()
}

micronaut {
    testRuntime("junit5")
    processing {
        incremental(true)
        annotations("com.tolearn.*")
    }
}

dependencies {

    implementation("io.grpc:protoc-gen-grpc-kotlin:1.0.0:jdk7@jar")
    api("io.grpc:grpc-kotlin-stub:1.0.0")

    implementation("io.micronaut:micronaut-validation")
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:${kotlinVersion}")
    implementation("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}")
    implementation("io.micronaut.kotlin:micronaut-kotlin-runtime")
    implementation("io.micronaut:micronaut-runtime")
    implementation("io.micronaut.grpc:micronaut-grpc-runtime")
    implementation("javax.annotation:javax.annotation-api")
    implementation("io.micronaut:micronaut-http-client")
    runtimeOnly("ch.qos.logback:logback-classic")
    runtimeOnly("com.fasterxml.jackson.module:jackson-module-kotlin")
}


application {
    mainClass.set("com.tolearn.ApplicationKt")
}

java {
    sourceCompatibility = JavaVersion.toVersion("11")
}

tasks {
    compileKotlin {
        kotlinOptions {
            jvmTarget = "11"
        }
    }
    compileTestKotlin {
        kotlinOptions {
            jvmTarget = "11"
        }
    }


}
sourceSets {
    main {
        java {
            srcDirs("build/generated/source/proto/main/grpc")
            srcDirs("build/generated/source/proto/main/java")
            srcDirs 'build/generated/source/proto/main/grpckt'
        }
    }
}

protobuf {
    protoc { artifact = "com.google.protobuf:protoc:3.14.0" }
    plugins {
        grpc { artifact = "io.grpc:protoc-gen-grpc-java:1.34.1" }
        grpckt { artifact = "io.grpc:protoc-gen-grpc-kotlin:1.0.0:jdk7@jar" }
    }
    generateProtoTasks {
        all()*.plugins {
            grpc {}
            grpckt {}
        }
    }
}

gradle.properties

micronautVersion=2.2.2
kotlinVersion=1.4.10

Full logs when I try to debug the application inside of IntelliJ

C:JDKsjdk-11.0.6binjava.exe "-javaagent:C:Program FilesJetBrainsIntelliJ IDEA Community Edition 2020.1libidea_rt.jar=57835:C:Program FilesJetBrainsIntelliJ IDEA Community Edition 2020.1bin" -Dfile.encoding=UTF-8 -classpath C:_dtoLearndemo-moneybuildclassesjavamain;C:_dtoLearndemo-moneybuildclasseskotlinmain;C:_dtoLearndemo-moneybuildtmpkapt3classesmain;C:_dtoLearndemo-moneybuildresourcesmain;C:UsersCast.gradlecachesmodules-2files-2.1io.grpcgrpc-kotlin-stub1.0.0a9b64135291f02726f437bf82822142dea3d963dgrpc-kotlin-stub-1.0.0.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.grpcprotoc-gen-grpc-kotlin1.0.0d6c8cbe29c60b202165593be5244ce43d37378acprotoc-gen-grpc-kotlin-1.0.0-jdk7.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.micronautmicronaut-validation2.2.24c9978ae69745ab3c5afd37d3c2e6c7f5a59190bmicronaut-validation-2.2.2.jar;C:UsersCast.gradlecachesmodules-2files-2.1org.jetbrains.kotlinkotlin-stdlib-jdk81.4.10998caa30623f73223194a8b657abd2baec4880eakotlin-stdlib-jdk8-1.4.10.jar;C:UsersCast.gradlecachesmodules-2files-2.1org.jetbrains.kotlinkotlin-reflect1.4.10e2b3c6695eee6085e606d96d685396dce23a3a06kotlin-reflect-1.4.10.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.micronaut.kotlinmicronaut-kotlin-runtime2.2.0b8b24a7e5ea4d68afd6edc283f2b1f944bbf2cc7micronaut-kotlin-runtime-2.2.0.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.micronautmicronaut-http-client2.2.2740a9b3ee54d66b838675e62df3c9bbdd8f1028bmicronaut-http-client-2.2.2.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.micronaut.grpcmicronaut-grpc-runtime2.2.01ed2e5c0f592d2f92eab105f60293f0c1cab6e92micronaut-grpc-runtime-2.2.0.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.micronautmicronaut-runtime2.2.2ffee1b2088cd3bd699646940dc37ccc537d6f77micronaut-runtime-2.2.2.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.micronautmicronaut-inject2.2.2dbbd8cf931e3714ef0e9ce635a1023a383785c25micronaut-inject-2.2.2.jar;C:UsersCast.gradlecachesmodules-2files-2.1javax.annotationjavax.annotation-api1.3.2934c04d3cfef185a8008e7bf34331b79730a9d43javax.annotation-api-1.3.2.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.grpcgrpc-protobuf1.33.14999a8c87e4264be11749b0e3c82526fb7481dafgrpc-protobuf-1.33.1.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.grpcgrpc-stub1.33.1cf2c3b997646a3f065efbaa72528dc7c67e80d77grpc-stub-1.33.1.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.micronautmicronaut-http2.2.23e8dbd9635f2ae40acf95dfeecf424cc46d759a0micronaut-http-2.2.2.jar;C:UsersCast.gradlecachesmodules-2files-2.1org.slf4jslf4j-api1.7.2677100a62c2e6f04b53977b9f541044d7d722693dslf4j-api-1.7.26.jar;C:UsersCast.gradlecachesmodules-2files-2.1javax.validationvalidation-api2.0.1.Finalcb855558e6271b1b32e716d24cb85c7f583ce09evalidation-api-2.0.1.Final.jar;C:UsersCast.gradlecachesmodules-2files-2.1org.jetbrains.kotlinkotlin-stdlib-jdk71.4.1030e46450b0bb3dbf43898d2f461be4a942784780kotlin-stdlib-jdk7-1.4.10.jar;C:UsersCast.gradlecachesmodules-2files-2.1org.jetbrains.kotlinkotlin-stdlib1.4.10ea29e063d2bbe695be13e9d044dcfb0c7add398ekotlin-stdlib-1.4.10.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.micronautmicronaut-http-client-core2.2.2b939e521a859d2f691f352d2d274693d2e979039micronaut-http-client-core-2.2.2.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.micronautmicronaut-http-netty2.2.2d95de1cfb8f14ebe7c025ed1d994734bdc97aa76micronaut-http-netty-2.2.2.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.micronautmicronaut-websocket2.2.26b9727c73e352f3c2b8ad86f74f172de465c5035micronaut-websocket-2.2.2.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.nettynetty-handler-proxy4.1.56.Final3acd2ead521786303faf2f85308b98ba174c53b6netty-handler-proxy-4.1.56.Final.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.micronaut.grpcmicronaut-grpc-client-runtime2.2.089ebc47606ca77e186a3e182ac5eccd0cfce193emicronaut-grpc-client-runtime-2.2.0.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.micronaut.grpcmicronaut-grpc-server-runtime2.2.0f4e9472b6124f5e7db1ce229c7a1059db6589b84micronaut-grpc-server-runtime-2.2.0.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.micronautmicronaut-aop2.2.21389d1a032d2d6599c132e3f1daab239724e691dmicronaut-aop-2.2.2.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.reactivex.rxjava2rxjava2.2.1018e9edc67e0abaa03713eeb9ca2cb0e30c859de4rxjava-2.2.10.jar;C:UsersCast.gradlecachesmodules-2files-2.1com.fasterxml.jackson.datatypejackson-datatype-jdk82.11.2d4c1933a8d62db65c3d5a5cd809511e021a189c0jackson-datatype-jdk8-2.11.2.jar;C:UsersCast.gradlecachesmodules-2files-2.1com.fasterxml.jackson.datatypejackson-datatype-jsr3102.11.2e6235e5eb3cf3edd2a95cd0dc96bc48aeb309e8ajackson-datatype-jsr310-2.11.2.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.micronautmicronaut-core2.2.2c85844828723dcd0ccbf9fa70cb406d6c49d083bmicronaut-core-2.2.2.jar;C:UsersCast.gradlecachesmodules-2files-2.1org.yamlsnakeyaml1.26a78a8747147d2c5807683e76ec2b633e95c14fe9snakeyaml-1.26.jar;C:UsersCast.gradlecachesmodules-2files-2.1javax.injectjavax.inject16975da39a7040257bd51d21a231b76c915872d38javax.inject-1.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.grpcgrpc-protobuf-lite1.33.11972b32eca6661ac99f0d0d1f6bc78836a0aaa98grpc-protobuf-lite-1.33.1.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.grpcgrpc-api1.33.1110c50b7376a5083392a35cace95fbe121fefbc3grpc-api-1.33.1.jar;C:UsersCast.gradlecachesmodules-2files-2.1com.google.code.findbugsjsr3053.0.225ea2e8b0c338a877313bd4672d3fe056ea78f0djsr305-3.0.2.jar;C:UsersCast.gradlecachesmodules-2files-2.1com.google.protobufprotobuf-java3.14.0bb6430f70647fc349fffd1690ddb889dc3ea6699protobuf-java-3.14.0.jar;C:UsersCast.gradlecachesmodules-2files-2.1com.google.api.grpcproto-google-common-protos1.17.040471bf2045151c17da555889b5550fcfd5224a8proto-google-common-protos-1.17.0.jar;C:UsersCast.gradlecachesmodules-2files-2.1com.google.guavaguava29.0-androida51b7d9cbfcce79a88c961907c1767c6de201f31guava-29.0-android.jar;C:UsersCast.gradlecachesmodules-2files-2.1com.google.errorproneerror_prone_annotations2.3.4dac170e4594de319655ffb62f41cbd6dbb5e601eerror_prone_annotations-2.3.4.jar;C:UsersCast.gradlecachesmodules-2files-2.1org.jetbrains.kotlinkotlin-stdlib-common1.4.106229be3465805c99db1142ad75e6c6ddeac0b04ckotlin-stdlib-common-1.4.10.jar;C:UsersCast.gradlecachesmodules-2files-2.1org.jetbrainsannotations13.0919f0dfe192fb4e063e7dacadee7f8bb9a2672a9annotations-13.0.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.micronautmicronaut-buffer-netty2.2.2fec1f3c421efbffaefa261e85d0f967b5157cd52micronaut-buffer-netty-2.2.2.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.nettynetty-codec-http24.1.56.Final124a9dc7d71e1d8df8cddf588f52f3a353ed30c6netty-codec-http2-4.1.56.Final.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.nettynetty-codec-http4.1.56.Finalb67fa83d89476f66de30fa0808cf2fd019a43a06netty-codec-http-4.1.56.Final.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.nettynetty-handler4.1.56.Final6a3ccbc2c9d0b462643a1904ae6cdb84169546netty-handler-4.1.56.Final.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.nettynetty-codec-socks4.1.56.Final6bda6496c20c477d475e63934571eebdd07560e1netty-codec-socks-4.1.56.Final.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.nettynetty-codec4.1.56.Final2d828cca651f2a37de5735f0d79cbe77228c9d21netty-codec-4.1.56.Final.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.nettynetty-transport4.1.56.Final8809fc38a761463f2f43032918e9d455a622f6benetty-transport-4.1.56.Final.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.nettynetty-buffer4.1.56.Final92466b8de0e325a906c53bbaa9585091ef22001dnetty-buffer-4.1.56.Final.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.nettynetty-common4.1.56.Final8e4888cfc66b7ec5a9fb291d9593511481274089netty-common-4.1.56.Final.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.micronaut.grpcmicronaut-grpc-annotation2.2.0cecd044579bcbb555bea1f74becc172df8131fd1micronaut-grpc-annotation-2.2.0.jar;C:UsersCast.gradlecachesmodules-2files-2.1org.reactivestreamsreactive-streams1.0.3d9fb7a7926ffa635b3dcaa5049fb2bfa25b3e7d0reactive-streams-1.0.3.jar;C:UsersCast.gradlecachesmodules-2files-2.1com.github.spotbugsspotbugs-annotations4.0.3755cc5d84d32b31beeaf8597181f0fc4eac98e16spotbugs-annotations-4.0.3.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.grpcgrpc-context1.33.15d312ce1acad9869f118f01cef70a1d5ae7657a8grpc-context-1.33.1.jar;C:UsersCast.gradlecachesmodules-2files-2.1com.google.guavafailureaccess1.0.11dcf1de382a0bf95a3d8b0849546c88bac1292c9failureaccess-1.0.1.jar;C:UsersCast.gradlecachesmodules-2files-2.1com.google.guavalistenablefuture9999.0-empty-to-avoid-conflict-with-guavab421526c5f297295adef1c886e5246c39d4ac629listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar;C:UsersCast.gradlecachesmodules-2files-2.1org.checkerframeworkchecker-compat-qual2.5.5435dc33e3019c9f019e15f01aa111de9d6b2b79cchecker-compat-qual-2.5.5.jar;C:UsersCast.gradlecachesmodules-2files-2.1com.google.j2objcj2objc-annotations1.3ba035118bc8bac37d7eff77700720999acd9986dj2objc-annotations-1.3.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.nettynetty-resolver4.1.56.Final548076140d58591265533418529e28c7ebbf8422netty-resolver-4.1.56.Final.jar;C:UsersCast.gradlecachesmodules-2files-2.1com.fasterxml.jackson.modulejackson-module-kotlin2.11.3ad8d29545c5ab0cdd6d49ee38f7ece8d9f772815jackson-module-kotlin-2.11.3.jar;C:UsersCast.gradlecachesmodules-2files-2.1ch.qos.logbacklogback-classic1.2.37c4f3c474fb2c041d8028740440937705ebb473alogback-classic-1.2.3.jar;C:UsersCast.gradlecachesmodules-2files-2.1org.jetbrains.kotlinxkotlinx-coroutines-core1.3.35bac48cf5828e9b006f3b1ef6e37d2a70c2e7321kotlinx-coroutines-core-1.3.3.jar;C:UsersCast.gradlecachesmodules-2files-2.1com.typesafeconfig1.4.119058a07624a87f90d129af7cd9c68bee94535a9config-1.4.1.jar;C:UsersCast.gradlecachesmodules-2files-2.1com.fasterxml.jackson.corejackson-databind2.11.34f7b27416934dc929bb6c2d2c5fe521829e6a4ecjackson-databind-2.11.3.jar;C:UsersCast.gradlecachesmodules-2files-2.1com.fasterxml.jackson.corejackson-annotations2.11.325d4e9c777e7a8805c4a000a8629d3009c779c9bjackson-annotations-2.11.3.jar;C:UsersCast.gradlecachesmodules-2files-2.1ch.qos.logbacklogback-core1.2.3864344400c3d4d92dfeb0a305dc87d953677c03clogback-core-1.2.3.jar;C:UsersCast.gradlecachesmodules-2files-2.1org.codehaus.mojoanimal-sniffer-annotations1.18f7aa683ea79dc6681ee9fb95756c999acbb62f5danimal-sniffer-annotations-1.18.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.grpcgrpc-netty1.33.1db8c0e98533e5b57264dac2ef827661724f2575fgrpc-netty-1.33.1.jar;C:UsersCast.gradlecachesmodules-2files-2.1com.fasterxml.jackson.corejackson-core2.11.3c2351800432bdbdd8284c3f5a7f0782a352aa84ajackson-core-2.11.3.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.grpcgrpc-core1.33.155343c9703cd8a44cc2978b117b0a964d470e263grpc-core-1.33.1.jar;C:UsersCast.gradlecachesmodules-2files-2.1io.perfmarkperfmark-api.19.02bfc352777fa6e27ad1e11d11ea55651ba93236bperfmark-api-0.19.0.jar;C:UsersCast.gradlecachesmodules-2files-2.1com.google.code.gsongson2.8.69180733b7df8542621dc12e21e87557e8c99b8cbgson-2.8.6.jar;C:UsersCast.gradlecachesmodules-2files-2.1com.google.androidannotations4.1.1.4a1678ba907bf92691d879fef34e1a187038f9259annotations-4.1.1.4.jar com.tolearn.ApplicationKt
13:56:09.732 [main] ERROR io.micronaut.runtime.Micronaut - Error starting Micronaut server: Error instantiating bean of type  [io.micronaut.grpc.server.GrpcEmbeddedServer]

Message: kotlin.jvm.internal.FunctionReferenceImpl.<init>(ILjava/lang/Object;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;I)V
Path Taken: new GrpcEmbeddedServer(ApplicationContext applicationContext,ApplicationConfiguration applicationConfiguration,GrpcServerConfiguration grpcServerConfiguration,[ServerBuilder serverBuilder],ApplicationEventPublisher eventPublisher,ComputeInstanceMetadataResolver computeInstanceMetadataResolver,List metadataContributors)
io.micronaut.context.exceptions.BeanInstantiationException: Error instantiating bean of type  [io.micronaut.grpc.server.GrpcEmbeddedServer]

Message: kotlin.jvm.internal.FunctionReferenceImpl.<init>(ILjava/lang/Object;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;I)V
Path Taken: new GrpcEmbeddedServer(ApplicationContext applicationContext,ApplicationConfiguration applicationConfiguration,GrpcServerConfiguration grpcServerConfiguration,[ServerBuilder serverBuilder],ApplicationEventPublisher eventPublisher,ComputeInstanceMetadataResolver computeInstanceMetadataResolver,List metadataContributors)
    at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1925)
    at io.micronaut.context.DefaultBeanContext.createAndRegisterSingletonInternal(DefaultBeanContext.java:2679)
    at io.micronaut.context.DefaultBeanContext.createAndRegisterSingleton(DefaultBeanContext.java:2665)
    at io.micronaut.context.DefaultBeanContext.getBeanForDefinition(DefaultBeanContext.java:2337)
    at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:2311)
    at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:1245)
    at io.micronaut.context.AbstractBeanDefinition.getBeanForConstructorArgument(AbstractBeanDefinition.java:1013)
    at io.micronaut.grpc.server.$GrpcEmbeddedServerDefinition.build(Unknown Source)
    at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1898)
    at io.micronaut.context.DefaultBeanContext.createAndRegisterSingletonInternal(DefaultBeanContext.java:2679)
    at io.micronaut.context.DefaultBeanContext.createAndRegisterSingleton(DefaultBeanContext.java:2665)
    at io.micronaut.context.DefaultBeanContext.getBeanForDefinition(DefaultBeanContext.java:2337)
    at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:2311)
    at io.micronaut.context.DefaultBeanContext.findBean(DefaultBeanContext.java:1266)
    at io.micronaut.context.DefaultBeanContext.findBean(DefaultBeanContext.java:744)
    at io.micronaut.context.BeanLocator.findBean(BeanLocator.java:149)
    at io.micronaut.runtime.Micronaut.start(Micronaut.java:66)
    at com.tolearn.ApplicationKt.main(Application.kt:8)
Caused by: java.lang.NoSuchMethodError: kotlin.jvm.internal.FunctionReferenceImpl.<init>(ILjava/lang/Object;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;I)V
    at com.tolearn.endpoint.DemoMoneyServiceGrpcKt$DemoMoneyServiceCoroutineImplBase$bindService$1.<init>(DemoMoneyGrpcKt.kt)
    at com.tolearn.endpoint.DemoMoneyServiceGrpcKt$DemoMoneyServiceCoroutineImplBase.bindService(DemoMoneyGrpcKt.kt:90)
    at io.grpc.internal.AbstractServerImplBuilder.addService(AbstractServerImplBuilder.java:120)
    at io.grpc.internal.AbstractServerImplBuilder.addService(AbstractServerImplBuilder.java:56)
    at io.micronaut.grpc.server.GrpcServerBuilder.serverBuilder(GrpcServerBuilder.java:58)
    at io.micronaut.grpc.server.$GrpcServerBuilder$ServerBuilder0Definition.build(Unknown Source)
    at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1898)
    ... 17 common frames omitted

Process finished with exit code 1

Logs when I try to gradle run from command line

C:_dtoLearndemo-money>gradle run

> Task :run FAILED
14:43:44.395 [main] ERROR io.micronaut.runtime.Micronaut - Error starting Micronaut server: Error instantiating bean of type  [io.micronaut.grpc.server.GrpcEmbeddedServer]

Message: kotlin.jvm.internal.FunctionReferenceImpl.<init>(ILjava/lang/Object;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;I)V
Path Taken: new GrpcEmbeddedServer(ApplicationContext applicationContext,ApplicationConfiguration applicationConfiguration,GrpcServerConfiguration grpcServerConfiguration,[ServerBuilder serverBuilder],ApplicationEventPublisher eventPublisher,ComputeInstanceMetadataResolver computeInstanceMetadataResolver,List metadataContributors)
io.micronaut.context.exceptions.BeanInstantiationException: Error instantiating bean of type  [io.micronaut.grpc.server.GrpcEmbeddedServer]

Message: kotlin.jvm.internal.FunctionReferenceImpl.<init>(ILjava/lang/Object;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;I)V
Path Taken: new GrpcEmbeddedServer(ApplicationContext applicationContext,ApplicationConfiguration applicationConfiguration,GrpcServerConfiguration grpcServerConfiguration,[ServerBuilder serverBuilder],ApplicationEventPublisher eventPublisher,ComputeInstanceMetadataResolver computeInstanceMetadataResolver,List metadataContributors)
        at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1925)
        at io.micronaut.context.DefaultBeanContext.createAndRegisterSingletonInternal(DefaultBeanContext.java:2679)
        at io.micronaut.context.DefaultBeanContext.createAndRegisterSingleton(DefaultBeanContext.java:2665)
        at io.micronaut.context.DefaultBeanContext.getBeanForDefinition(DefaultBeanContext.java:2337)
        at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:2311)
        at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:1245)
        at io.micronaut.context.AbstractBeanDefinition.getBeanForConstructorArgument(AbstractBeanDefinition.java:1013)
        at io.micronaut.grpc.server.$GrpcEmbeddedServerDefinition.build(Unknown Source)
        at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1898)
        at io.micronaut.context.DefaultBeanContext.createAndRegisterSingletonInternal(DefaultBeanContext.java:2679)
        at io.micronaut.context.DefaultBeanContext.createAndRegisterSingleton(DefaultBeanContext.java:2665)
        at io.micronaut.context.DefaultBeanContext.getBeanForDefinition(DefaultBeanContext.java:2337)
        at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:2311)
        at io.micronaut.context.DefaultBeanContext.findBean(DefaultBeanContext.java:1266)
        at io.micronaut.context.DefaultBeanContext.findBean(DefaultBeanContext.java:744)
        at io.micronaut.context.BeanLocator.findBean(BeanLocator.java:149)
        at io.micronaut.runtime.Micronaut.start(Micronaut.java:66)
        at com.tolearn.ApplicationKt.main(Application.kt:8)
Caused by: java.lang.NoSuchMethodError: kotlin.jvm.internal.FunctionReferenceImpl.<init>(ILjava/lang/Object;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;I)V
        at com.tolearn.endpoint.DemoMoneyServiceGrpcKt$DemoMoneyServiceCoroutineImplBase$bindService$1.<init>(DemoMoneyGrpcKt.kt)
        at com.tolearn.endpoint.DemoMoneyServiceGrpcKt$DemoMoneyServiceCoroutineImplBase.bindService(DemoMoneyGrpcKt.kt:90)
        at io.grpc.internal.AbstractServerImplBuilder.addService(AbstractServerImplBuilder.java:120)
        at io.grpc.internal.AbstractServerImplBuilder.addService(AbstractServerImplBuilder.java:56)
        at io.micronaut.grpc.server.GrpcServerBuilder.serverBuilder(GrpcServerBuilder.java:58)
        at io.micronaut.grpc.server.$GrpcServerBuilder$ServerBuilder0Definition.build(Unknown Source)
        at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1898)
        ... 17 common frames omitted

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':run'.
> Process 'command 'C:JDKsjdk-11.0.6binjava.exe'' finished with non-zero exit value 1

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 5s
9 actionable tasks: 1 executed, 8 up-to-date

C:_dtoLearndemo-money> 

IntelliJ

Kotlin 1.4 and Java11

I guess it is an issue with version conflicts but I can’t imagine what try.

So my straight question is, what can I try in order to fix this issue? Possible solution may be related to the fact I am using kotlin-stdlib-jdk8:1.4.10. If so, what can I try or maybe downgrade?

It is interesting that I can build successfully the application but I am getting the error mentioned above only when I try execute


Get this bounty!!!

#StackBounty: #kotlin #gradle #cdi #quarkus How to resolve multi-module classpath beans in Quarkus, Kotlin and Gradle?

Bounty: 50

In Spring it’s possible to define bean dependencies in separate modules, which are then resolved via the classpath at runtime. Is it possible to do similar in Quarkus?

For example, a multi-module setup like so:

- service
- service-test
- service-artifact

In Spring it’s possible to define @Configuration in the service module, that resolves concrete dependencies at runtime via the classpath of its current context, either service-test or service-artifact, allowing injection of dummy or test dependencies when under test for example. For example, a class in service requires an instance of SomeInterface. The implementation of SomeInterface is defined in either the -test or -artifact module.

Where I have tried to replicate a Spring-style setup as above in Quarkus, ArC validation is failing with UnsatisfiedResolutionException on the build of the service module, even though everywhere it is actually consumed provides the correct dependencies.

Is there a way around this with Quarkus?

EDIT:

root project build.gradle.kts:

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

    plugins {
        kotlin("jvm") version "1.3.72"
        kotlin("plugin.allopen") version "1.3.72"
    }

allprojects {

    group = "my-group"
    version = "1.0.0-SNAPSHOT"

    repositories {
        mavenLocal()
        mavenCentral()
    }
}

subprojects {

    apply {
        plugin("kotlin")
        plugin("kotlin-allopen")
    }

    java {
        sourceCompatibility = JavaVersion.VERSION_11
        targetCompatibility = JavaVersion.VERSION_11
    }
    
    allOpen {
        annotation("javax.ws.rs.Path")
        annotation("javax.enterprise.context.ApplicationScoped")
        annotation("io.quarkus.test.junit.QuarkusTest")
    }

    apply {
        plugin("kotlin")
    }

    dependencies {
        implementation("org.jetbrains.kotlin:kotlin-reflect")
        implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
    }

    tasks.withType<KotlinCompile> {
        kotlinOptions.jvmTarget = JavaVersion.VERSION_11.toString()
        kotlinOptions.javaParameters = true
    }
}

build.gradle.kts for service:

import io.quarkus.gradle.tasks.QuarkusDev

plugins {
    id("io.quarkus") version "1.9.1.Final"
}

apply {
    plugin("io.quarkus")
}

dependencies {
    implementation(project(":common:model"))
    implementation(enforcedPlatform("io.quarkus:quarkus-universe-bom:1.9.1.Final"))
    implementation("io.quarkus:quarkus-kotlin")
}

build.gradle.kts for service-test:

import io.quarkus.gradle.tasks.QuarkusDev

plugins {
    id("io.quarkus") version "1.9.1.Final"
}

apply {
    plugin("io.quarkus")
}

dependencies {
    implementation(project(":service"))
    implementation(enforcedPlatform("io.quarkus:quarkus-universe-bom:1.9.1.Final"))
    implementation("io.quarkus:quarkus-kotlin")
    testImplementation("io.quarkus:quarkus-junit5")
}

build.gradle.kts for service-artifact:

import io.quarkus.gradle.tasks.QuarkusDev

plugins {
    id("io.quarkus") version "1.9.1.Final"
}

apply {
    plugin("io.quarkus")
}

dependencies {
    implementation(project(":service"))
    implementation(enforcedPlatform("io.quarkus:quarkus-universe-bom:1.9.1.Final"))
    implementation("io.quarkus:quarkus-kotlin")
    implementation("io.quarkus:quarkus-scheduler")
}


Get this bounty!!!

#StackBounty: #android #kotlin #exoplayer ExoPlayer how to show loading first frame during loading of video

Bounty: 100

I’m having an API serving the video URI and a (preloaded!) first frame URI. How can I initialize the ExoPlayer with the already available first frame?

@Singleton
class MediaPlayer @Inject constructor(private val context: Context) {

    companion object {
        var exoPlayer: SimpleExoPlayer? = null
        var pauseItem = false
    }

    fun initializeExoplayer(uri: Uri): SimpleExoPlayer {
        if (exoPlayer != null) {
            resetPlayer()
        }

        val trackSelector = DefaultTrackSelector()

        trackSelector.setParameters(
            DefaultTrackSelector.ParametersBuilder()
                .setForceLowestBitrate(true)
                .setMaxAudioBitrate(128_000)
        )

        exoPlayer = ExoPlayerFactory.newSimpleInstance(context, trackSelector)

        val mediaSource = createMediaSource(uri)
        val loopingSource = LoopingMediaSource(mediaSource)

        exoPlayer?.prepare(loopingSource)
        exoPlayer?.volume = 1f

        return exoPlayer!!
    }

    fun resetPlayer() {
        exoPlayer?.playWhenReady = false
        exoPlayer?.stop()
        exoPlayer?.release()
        exoPlayer = null
    }

    private fun createMediaSource(uri: Uri): MediaSource {
        val userAgent = Util.getUserAgent(context, "ExoPlayerIntro")
        val dataSourceFactory = DefaultDataSourceFactory(context, userAgent)

        val mediaSource =
            ProgressiveMediaSource.Factory(dataSourceFactory, DefaultExtractorsFactory())
                .createMediaSource(uri)

        return Objects.requireNonNull(mediaSource, "MediaSource cannot be null")
    }
}

I’ve also asked the Google Team:
https://github.com/google/ExoPlayer/issues/8139


Get this bounty!!!

#StackBounty: #android #kotlin How in Kotlin on Android can a null pointer exception occur in an immutable list during a or each loop?

Bounty: 100

I’m getting a RARE null pointer exception in the following code:

class Artist {
  fun draw(canvas: Canvas, state: State){
    state.drawableObjects.forEach { 
      it.draw(canvas) //NULL POINTER!?! Can not call draw(Canvas) on null object
    }
  }
}

class State {
  var drawableObjects = listOf<DrawableObject>
    set(value) {
      field = value.filter { it.isVisible }
    }
}

class DrawableObject {
   val isVisible = true
   fun draw(canvas: Canvas) { }
}

How is this possible? The list drawableObjects is immutable. It also does not allow null objects. When the list is changed an entirely new list is set to prevent modification during the draw call.

I should definitely mention that multiple threads are involved. 2 threads only. One calling Artist.draw() and a second calling State.drawableObjects = listOf()


Get this bounty!!!

#StackBounty: #android #kotlin #google-vision #google-mlkit Reduce tracking window using google mlkit vision samples

Bounty: 500

I would like to reduce the reduce bar code tracking window when using the google vision api. There are some answers here but they feel a bit outdated.

I’m using google’s sample: https://github.com/googlesamples/mlkit/tree/master/android/vision-quickstart

Currently, I try to figure out if a barcode is inside my overlay box inside BarcodeScannerProcessor onSuccess callback:

override fun onSuccess(barcodes: List<Barcode>, graphicOverlay: GraphicOverlay) {
    if(barcodes.isEmpty())
      return;

    for(barcode in barcodes) {
      val center = Point(graphicOverlay.imageWidth / 2, graphicOverlay.imageHeight / 2)
      val rectWidth = graphicOverlay.imageWidth * Settings.OverlayWidthFactor
      val rectHeight = graphicOverlay.imageHeight * Settings.OverlayHeightFactor

      val left = center.x - rectWidth / 2
      val top = center.y - rectHeight / 2
      val right = center.x + rectWidth / 2
      val bottom = center.y + rectHeight / 2

      val rect = Rect(left.toInt(), top.toInt(), right.toInt(), bottom.toInt())

      val contains = rect.contains(barcode.boundingBox!!)
      val color = if(contains) Color.GREEN else Color.RED

      graphicOverlay.add(BarcodeGraphic(graphicOverlay, barcode, "left: ${barcode.boundingBox!!.left}", color))
    }
}

Y-wise it works perfectly, but the X values from barcode.boundingBox e.g. barcode.boundingBox.left seems to have an offset. Is it based on what’s being calculated in GraphicOverlay?

I’m expecting the value below to be close to 0, but the offset is about 90 here:

enter image description here

Or perhaps it’s more efficient to crop the image according to the box?


Get this bounty!!!

#StackBounty: #android #kotlin #android-camera2 How to take a picture where all settings are set manually including the flash without m…

Bounty: 100

I used the latest Camera2Basic sample program as a source for my trials:

https://github.com/android/camera-samples.git

Basically I configured the CaptureRequest before I call the capture() function in the takePhoto() function like this:

    private fun prepareCaptureRequest(captureRequest: CaptureRequest.Builder) {
    //set all needed camera settings here
    captureRequest.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_OFF)

    captureRequest.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF);
    //captureRequest.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_CANCEL);
    //captureRequest.set(CaptureRequest.CONTROL_AWB_LOCK, true);
    captureRequest.set(CaptureRequest.CONTROL_AWB_MODE, CaptureRequest.CONTROL_AWB_MODE_OFF);
    captureRequest.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF);
    //captureRequest.set(CaptureRequest.CONTROL_AE_LOCK, true);
    //captureRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL);
    //captureRequest.set(CaptureRequest.NOISE_REDUCTION_MODE, CaptureRequest.NOISE_REDUCTION_MODE_FAST);

    //flash
    if (mState == CaptureState.PRECAPTURE){
        //captureRequest.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF);
        captureRequest.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF)
    }
    if (mState == CaptureState.TAKEPICTURE) {
        //captureRequest.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_SINGLE)
        //captureRequest.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
        captureRequest.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_SINGLE)
    }

    val iso = 100
    captureRequest.set(CaptureRequest.SENSOR_SENSITIVITY, iso)

    val fractionOfASecond = 750.toLong()
    captureRequest.set(CaptureRequest.SENSOR_EXPOSURE_TIME, 1000.toLong() * 1000.toLong() * 1000.toLong() / fractionOfASecond)
    //val exposureTime = 133333.toLong()
    //captureRequest.set(CaptureRequest.SENSOR_EXPOSURE_TIME, exposureTime)

    //val characteristics = cameraManager.getCameraCharacteristics(cameraId)
    //val configs: StreamConfigurationMap? = characteristics[CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP]
    //val frameDuration = 33333333.toLong()
    //captureRequest.set(CaptureRequest.SENSOR_FRAME_DURATION, frameDuration)

    val focusDistanceCm = 20.0.toFloat()    //20cm 
    captureRequest.set(CaptureRequest.LENS_FOCUS_DISTANCE, 100.0f / focusDistanceCm)

    //captureRequest.set(CaptureRequest.COLOR_CORRECTION_MODE, CameraMetadata.COLOR_CORRECTION_MODE_FAST)
    captureRequest.set(CaptureRequest.COLOR_CORRECTION_MODE, CaptureRequest.COLOR_CORRECTION_MODE_TRANSFORM_MATRIX)
    val colorTemp = 8000.toFloat();
    val rggb = colorTemperature(colorTemp)
    //captureRequest.set(CaptureRequest.COLOR_CORRECTION_TRANSFORM, colorTransform);
    captureRequest.set(CaptureRequest.COLOR_CORRECTION_GAINS, rggb);
}

but the picture that is returned never is the picture where the flash is at its brightest. This is on a Google Pixel 2 device.
As I only take one picture I am also not sure how to check some CaptureResult states to find the correct one as there is only one.
I already looked at the other solutions to similar problems here but they were either never really solved or somehow took the picture during capture preview which I don’t want.

Other strange observations are that on different devices the images are taken (also not always at the right moment), but then the manual values I set are not observed in the JPEG metadata of the image.

If needed I can put my git fork on github.


Get this bounty!!!

#StackBounty: #android-studio #kotlin #android-jetpack Why does LiveData only effect main layout and doesn't LiveData effect child …

Bounty: 50

FragmentHome load layout_home.xml, and layout_home.xml displays a recyclerview and a button named btnMain

recyclerview include the item layout layout_voice_item.xml, it displays a button named btnChild

I use displayCheckBox : LiveData<Boolean> to control whether both btnMain and btnChild are shown or not with the code android:visibility="@{!aHomeViewModel.displayCheckBox? View.VISIBLE: View.GONE}".

I find btnMain can be shown or not when I change the value of displayCheckBox, but btnChild keep to show, why?

FragmentHome.kt

class FragmentHome : Fragment() {

    private lateinit var binding: LayoutHomeBinding

    private val mHomeViewModel by lazy {
        getViewModel {
            HomeViewModel(provideRepository(mContext))
        }
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        binding = DataBindingUtil.inflate(
            inflater, R.layout.layout_home, container, false
        )
        binding.lifecycleOwner = this.viewLifecycleOwner
        binding.aHomeViewModel=mHomeViewModel

        val adapter = VoiceAdapters(mHomeViewModel)
        binding.mvoiceList.adapter=adapter
        mHomeViewModel.listVoiceBySort.observe(viewLifecycleOwner){
          adapter.submitList(it)
        }
        ...
        return binding.root
    }
}

HomeViewModel.kt

class HomeViewModel(private val mDBVoiceRepository: DBVoiceRepository) : ViewModel() {

    private val _displayCheckBox = MutableLiveData<Boolean>(true)
    val displayCheckBox : LiveData<Boolean> = _displayCheckBox

    fun setCheckBox(isDisplay:Boolean){
        _displayCheckBox.value = isDisplay
    }

    ...
}

VoiceAdapters.kt

class VoiceAdapters (private val aHomeViewModel: HomeViewModel):
        ListAdapter<MVoice, VoiceAdapters.VoiceViewHolder>(MVoiceDiffCallback()) {
    ...
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VoiceViewHolder {
        return VoiceViewHolder(
            LayoutVoiceItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        )
    }

    override fun onBindViewHolder(holder: VoiceViewHolder, position: Int) {
        val aMVoice = getItem(position)
        holder.bind(aHomeViewModel, aMVoice)
    }

    inner class VoiceViewHolder (private val binding: LayoutVoiceItemBinding):
          RecyclerView.ViewHolder(binding.root) {

        fun bind(mHomeViewModel: HomeViewModel, aMVoice: MVoice) {
            binding.aHomeViewModel = mHomeViewModel
            binding.executePendingBindings()
        }

    }

    ...
}
class MVoiceDiffCallback : DiffUtil.ItemCallback<MVoice>() {
    ...
}

layout_home.xml

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <import type="android.view.View" />

        <variable name="aHomeViewModel"
            type="info.dodata.voicerecorder.viewcontrol.HomeViewModel" />
    </data>

<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/mvoice_list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
            tools:listitem="@layout/layout_voice_item"            
        />

      <Button
            android:id="@+id/btnMain"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"         
            android:visibility="@{!aHomeViewModel.displayCheckBox? View.VISIBLE: View.GONE}"            
        />

</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

layout_voice_item.xml

<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">

<data>
    <import type="android.view.View" />
    <variable name="aHomeViewModel"
        type="info.dodata.voicerecorder.viewcontrol.HomeViewModel" />
</data>

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <Button
        android:id="@+id/btnChild"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:visibility="@{!aHomeViewModel.displayCheckBox? View.VISIBLE: View.GONE}"        
    />

</LinearLayout>
</layout>


Get this bounty!!!

#StackBounty: #android #kotlin #android-livedata How to access each element of LiveData<List<MVoice>> with Kotlin?

Bounty: 50

The Code A use for (aMovice in listVoiceBySort.value!!) to access each element of LiveData<List<MVoice>>.

But I don’t think it’s a good way because it uses listVoiceBySort.value!!, it’s ugly.

Is there a good way to access each element of LiveData<List<MVoice>>?

Code A

 val listVoiceBySort: LiveData<List<MVoice>> =_listVoiceBySort

 fun selectAllIDs(){
   for (aMovice in listVoiceBySort.value!!){
            selectedIDs.add(aMovice.id)
    }
 }


Get this bounty!!!

#StackBounty: #spring-boot #kotlin #spring-security #spring-webflux Force ServerAuthenticationFailureHandler for a given path in Spring…

Bounty: 100

I have two paths /foo and /bar. For /foo I have a custom authentication mechanism that I use. On /bar I have Basic authentication.

This setup works fine except one case. When I do not pass the AUTHORIZATION header in /foo then Basic auth kicks in instead of MyAuthenticationFailureHandler

Is there a way to set MyAuthenticationFailureHandler for a given path? Or maybe I messed up something with SecurityWebFiltersOrder?

My full security config:

bean<MyReactiveUserDetailsService>()
bean<MyReactiveAuthenticationManager>()
bean {
    ref<ServerHttpSecurity>()
        .securityMatcher {
            if (it.request.path.value().contains("/bar")) {
                ServerWebExchangeMatcher.MatchResult.match()
            } else {
                ServerWebExchangeMatcher.MatchResult.notMatch()
            }
        }
        .formLogin().disable()
        .csrf().disable()
        .logout().disable()
        .httpBasic()
        .and()
        .authorizeExchange()
        .pathMatchers("/bar/**")
        .hasRole("ADMIN")
        .anyExchange().permitAll()
        .and()
        .build()
}

bean {
    ref<ServerHttpSecurity>()
        .securityMatcher {
            if (it.request.path.value().contains("/bar")) {
                ServerWebExchangeMatcher.MatchResult.notMatch()
            } else {
                ServerWebExchangeMatcher.MatchResult.match()
            }
        }
        .httpBasic().disable()
        .formLogin().disable()
        .csrf().disable()
        .logout().disable()
        .authorizeExchange()
        .pathMatchers(
            HttpMethod.POST,
            "/foo/**"
        ).hasRole(
            "ABRACADABRA"
        )
        .anyExchange().permitAll()
        .and()
        .addFilterAt(
            authenticationWebFilter(ref(), ref()),
            SecurityWebFiltersOrder.AUTHENTICATION
        )
        .build()
}
}

private fun authenticationWebFilter(
    reactiveAuthenticationManager: ReactiveAuthenticationManager,
    objectMapper: ObjectMapper
) =
    AuthenticationWebFilter(reactiveAuthenticationManager).apply {
        setServerAuthenticationConverter(MyAuthenticationConverter())
        setRequiresAuthenticationMatcher(
            ServerWebExchangeMatchers.pathMatchers(
                HttpMethod.POST,
               "/foo/**"
            )
        )
        setAuthenticationFailureHandler(MyAuthenticationFailureHandler(objectMapper))
    }

class MyAuthenticationConverter : ServerAuthenticationConverter {
    override fun convert(exchange: ServerWebExchange): Mono<Authentication> {
        val authHeader: String? = exchange.request.headers.getFirst(HttpHeaders.AUTHORIZATION)
        // ... 
        return when {
            isValid(authHeader, ...) -> {
                Mono.just(
                    UsernamePasswordAuthenticationToken(principal, credentials)
                )
            }
            else -> Mono.empty()
        }
    }
}

class MyAuthenticationFailureHandler(private val objectMapper: ObjectMapper) : ServerAuthenticationFailureHandler {
    override fun onAuthenticationFailure(
        webFilterExchange: WebFilterExchange,
        exception: AuthenticationException?
    ): Mono<Void> {
        val response = webFilterExchange.exchange.response
        response.apply {
            statusCode = HttpStatus.OK
            headers.contentType = MediaType.APPLICATION_JSON
            headers.set(HttpHeaders.WARNING, """199 warning "Invalid token"""")
        }

        return response.writeWith(
            Flux.just(
                DefaultDataBufferFactory().wrap(
                    objectMapper.writeValueAsBytes(
                        MyDto(
                            // ...
                        ).toSettingResponse()
                    )
                )
            )
        )
    }
}


Get this bounty!!!