mvysny / vaadin-on-kotlin

Writing full-stack statically-typed web apps on JVM at its simplest
https://www.vaadinonkotlin.eu/
MIT License
186 stars 17 forks source link

DataLoaderAdapter - IndexOutOfBoundsException due to endInclusive subtracting 1 #39

Closed jhult closed 4 years ago

jhult commented 4 years ago

In DataLoaderAdapter, endInclusive is subtracting 1. Why?

This is causing an IndexOutOfBoundsException for me.

mvysny commented 4 years ago

That's because it's "end inclusive" - it's how ranges in Kotlin work. For example if you wish to fetch 30 items starting from offset 300, you represent it with a Kotlin range of 300..329. However, how can I help with the IndexOutOfBoundsException please?

jhult commented 4 years ago

So inside the fetch function, should I be using endInclusive/last or range.length? Or I suppose it depends on what "end" or maximum my DataLoader function is expecting.

Here is an example class:

import com.github.mvysny.karibudsl.v10.grid
import com.github.mvysny.vokdataloader.DataLoader
import com.github.mvysny.vokdataloader.Filter
import com.github.mvysny.vokdataloader.SortClause
import com.github.vokorm.dataloader.length
import com.vaadin.flow.component.orderedlayout.HorizontalLayout
import com.vaadin.flow.router.Route
import eu.vaadinonkotlin.vaadin10.asDataProvider
import kotlin.streams.toList

@Route("gridtest")
class GridTest(): HorizontalLayout() {

    init {
        val dataLoader = DataLoaderTest()
        val dataProvider = dataLoader.asDataProvider{it}

        grid(dataProvider) {
            addColumn {
                it
            }
        }
    }
}

class DataLoaderTest : DataLoader<String> {

    private val items = listOf("1", "2", "3", "4", "5", "6", "7")

    init {
        println("items.size: ${items.size}")
    }

    override fun fetch(filter: Filter<String>?, sortBy: List<SortClause>, range: LongRange): List<String> {
        println("range: $range")
        println("range length: ${range.length.toInt()}")
        println("range first: ${range.first.toInt()}")
        println("range endInclusive: ${range.endInclusive.toInt()}")
        println("range last: ${range.last.toInt()}")

        return items.stream().limit(range.last).toList()

        //return items.subList(range.first.toInt(), range.last.toInt())
    }

    override fun getCount(filter: Filter<String>?): Long {
        return items.size.toLong()
    }
}

Using endInclusive/last for either stream.limit or subList gives this IndexOutOfBoundsException:

[INFO] 2019-11-19 17:09:53,006 ERROR c.v.f.s.DefaultErrorHandler#error - 
[INFO] java.lang.IndexOutOfBoundsException: Index 6 out of bounds for length 6
[INFO]  at jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64) ~[?:?]
[INFO]  at jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70) ~[?:?]
[INFO]  at jdk.internal.util.Preconditions.checkIndex(Preconditions.java:248) ~[?:?]
[INFO]  at java.util.Objects.checkIndex(Objects.java:373) ~[?:?]
[INFO]  at java.util.ArrayList.get(ArrayList.java:425) ~[?:?]
[INFO]  at com.vaadin.flow.data.provider.DataCommunicator.lambda$getJsonItems$3(DataCommunicator.java:615) ~[flow-data-2.1.0.rc2.jar:2.1.0.rc2]
[INFO]  at com.vaadin.flow.data.provider.DataCommunicator$$Lambda$987.0000000000000000.apply(Unknown Source) ~[?:?]
[INFO]  at java.util.stream.IntPipeline$1$1.accept(IntPipeline.java:186) ~[?:?]
[INFO]  at java.util.stream.Streams$RangeIntSpliterator.forEachRemaining(Streams.java:109) ~[?:?]
[INFO]  at java.util.Spliterator$OfInt.forEachRemaining(Spliterator.java:699) ~[?:?]
[INFO]  at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:497) ~[?:?]
[INFO]  at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:487) ~[?:?]
[INFO]  at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913) ~[?:?]
[INFO]  at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:239) ~[?:?]
[INFO]  at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578) ~[?:?]
[INFO]  at com.vaadin.flow.data.provider.DataCommunicator.getJsonItems(DataCommunicator.java:617) ~[flow-data-2.1.0.rc2.jar:2.1.0.rc2]
[INFO]  at com.vaadin.flow.data.provider.DataCommunicator.collectChangesToSend(DataCommunicator.java:560) ~[flow-data-2.1.0.rc2.jar:2.1.0.rc2]
[INFO]  at com.vaadin.flow.data.provider.DataCommunicator.flush(DataCommunicator.java:477) ~[flow-data-2.1.0.rc2.jar:2.1.0.rc2]
[INFO]  at com.vaadin.flow.data.provider.DataCommunicator.lambda$requestFlush$2f364bb9$1(DataCommunicator.java:425) ~[flow-data-2.1.0.rc2.jar:2.1.0.rc2]
[INFO]  at com.vaadin.flow.data.provider.DataCommunicator$$Lambda$556.0000000000000000.accept(Unknown Source) ~[?:?]
[INFO]  at com.vaadin.flow.internal.StateTree.lambda$runExecutionsBeforeClientResponse$1(StateTree.java:368) ~[flow-server-2.1.0.rc2.jar:2.1.0.rc2]
[INFO]  at com.vaadin.flow.internal.StateTree$$Lambda$729.0000000000000000.accept(Unknown Source) ~[?:?]
[INFO]  at java.util.ArrayList.forEach(ArrayList.java:1507) ~[?:?]
[INFO]  at com.vaadin.flow.internal.StateTree.runExecutionsBeforeClientResponse(StateTree.java:365) ~[flow-server-2.1.0.rc2.jar:2.1.0.rc2]
[INFO]  at com.vaadin.flow.server.communication.UidlWriter.encodeChanges(UidlWriter.java:411) ~[flow-server-2.1.0.rc2.jar:2.1.0.rc2]
[INFO]  at com.vaadin.flow.server.communication.UidlWriter.createUidl(UidlWriter.java:187) ~[flow-server-2.1.0.rc2.jar:2.1.0.rc2]
[INFO]  at com.vaadin.flow.server.communication.UidlWriter.createUidl(UidlWriter.java:225) ~[flow-server-2.1.0.rc2.jar:2.1.0.rc2]
[INFO]  at com.vaadin.flow.server.BootstrapHandler$BootstrapPageBuilder.getInitialUidl(BootstrapHandler.java:756) ~[flow-server-2.1.0.rc2.jar:2.1.0.rc2]
[INFO]  at com.vaadin.flow.server.BootstrapHandler$BootstrapPageBuilder.setupDocumentHead(BootstrapHandler.java:739) ~[flow-server-2.1.0.rc2.jar:2.1.0.rc2]
[INFO]  at com.vaadin.flow.server.BootstrapHandler$BootstrapPageBuilder.getBootstrapPage(BootstrapHandler.java:517) ~[flow-server-2.1.0.rc2.jar:2.1.0.rc2]
[INFO]  at com.vaadin.flow.server.BootstrapHandler.synchronizedHandleRequest(BootstrapHandler.java:458) ~[flow-server-2.1.0.rc2.jar:2.1.0.rc2]
[INFO]  at com.vaadin.flow.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:40) ~[flow-server-2.1.0.rc2.jar:2.1.0.rc2]
[INFO]  at com.vaadin.flow.server.VaadinService.handleRequest(VaadinService.java:1540) ~[flow-server-2.1.0.rc2.jar:2.1.0.rc2]
[INFO]  at com.github.mcollovati.vertx.vaadin.VertxVaadin.handleVaadinRequest(VertxVaadin.java:267) ~[vertx-vaadin-flow-14.0.0.jar:?]
[INFO]  at com.github.mcollovati.vertx.vaadin.VertxVaadin$$Lambda$370.0000000000000000.handle(Unknown Source) ~[?:?]
[INFO]  at io.vertx.ext.web.impl.RouteImpl.handleContext(RouteImpl.java:232) ~[vertx-web-3.7.1.jar:3.7.1]
[INFO]  at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:121) ~[vertx-web-3.7.1.jar:3.7.1]
[INFO]  at io.vertx.ext.web.impl.RoutingContextWrapper.next(RoutingContextWrapper.java:154) ~[vertx-web-3.7.1.jar:3.7.1]
[INFO]  at io.vertx.ext.web.handler.impl.StaticHandlerImpl.lambda$sendStatic$1(StaticHandlerImpl.java:197) ~[vertx-web-3.7.1.jar:3.7.1]
[INFO]  at io.vertx.ext.web.handler.impl.StaticHandlerImpl$$Lambda$421.0000000000000000.handle(Unknown Source) ~[?:?]
[INFO]  at io.vertx.core.impl.ContextImpl.lambda$null$0(ContextImpl.java:284) ~[vertx-core-3.7.1.jar:3.7.1]
[INFO]  at io.vertx.core.impl.ContextImpl$$Lambda$160.0000000000000000.handle(Unknown Source) ~[?:?]
[INFO]  at io.vertx.core.impl.ContextImpl.executeTask(ContextImpl.java:320) ~[vertx-core-3.7.1.jar:3.7.1]
[INFO]  at io.vertx.core.impl.EventLoopContext.lambda$executeAsync$0(EventLoopContext.java:38) ~[vertx-core-3.7.1.jar:3.7.1]
[INFO]  at io.vertx.core.impl.EventLoopContext$$Lambda$116.0000000000000000.run(Unknown Source) ~[?:?]
[INFO]  at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163) [netty-common-4.1.34.Final.jar:4.1.34.Final]
[INFO]  at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:404) [netty-common-4.1.34.Final.jar:4.1.34.Final]
[INFO]  at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:495) [netty-transport-4.1.34.Final.jar:4.1.34.Final]
[INFO]  at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:905) [netty-common-4.1.34.Final.jar:4.1.34.Final]
[INFO]  at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) [netty-common-4.1.34.Final.jar:4.1.34.Final]
[INFO]  at java.lang.Thread.run(Thread.java:831) [?:?]
[INFO] 2019-11-19 17:09:53,014 ERROR c.g.m.v.v.VertxVaadin#handleVaadinRequest - Error processing request {}/gridtest
[INFO] com.vaadin.flow.server.ServiceException: java.lang.IndexOutOfBoundsException: Index 6 out of bounds for length 6
[INFO]  at com.vaadin.flow.server.VaadinService.handleExceptionDuringRequest(VaadinService.java:1589) ~[flow-server-2.1.0.rc2.jar:2.1.0.rc2]
[INFO]  at com.vaadin.flow.server.VaadinService.handleRequest(VaadinService.java:1552) ~[flow-server-2.1.0.rc2.jar:2.1.0.rc2]
[INFO]  at com.github.mcollovati.vertx.vaadin.VertxVaadin.handleVaadinRequest(VertxVaadin.java:267) ~[vertx-vaadin-flow-14.0.0.jar:?]
[INFO]  at com.github.mcollovati.vertx.vaadin.VertxVaadin$$Lambda$370.0000000000000000.handle(Unknown Source) ~[?:?]
[INFO]  at io.vertx.ext.web.impl.RouteImpl.handleContext(RouteImpl.java:232) ~[vertx-web-3.7.1.jar:3.7.1]
[INFO]  at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:121) ~[vertx-web-3.7.1.jar:3.7.1]
[INFO]  at io.vertx.ext.web.impl.RoutingContextWrapper.next(RoutingContextWrapper.java:154) ~[vertx-web-3.7.1.jar:3.7.1]
[INFO]  at io.vertx.ext.web.handler.impl.StaticHandlerImpl.lambda$sendStatic$1(StaticHandlerImpl.java:197) ~[vertx-web-3.7.1.jar:3.7.1]
[INFO]  at io.vertx.ext.web.handler.impl.StaticHandlerImpl$$Lambda$421.0000000000000000.handle(Unknown Source) ~[?:?]
[INFO]  at io.vertx.core.impl.ContextImpl.lambda$null$0(ContextImpl.java:284) ~[vertx-core-3.7.1.jar:3.7.1]
[INFO]  at io.vertx.core.impl.ContextImpl$$Lambda$160.0000000000000000.handle(Unknown Source) ~[?:?]
[INFO]  at io.vertx.core.impl.ContextImpl.executeTask(ContextImpl.java:320) ~[vertx-core-3.7.1.jar:3.7.1]
[INFO]  at io.vertx.core.impl.EventLoopContext.lambda$executeAsync$0(EventLoopContext.java:38) ~[vertx-core-3.7.1.jar:3.7.1]
[INFO]  at io.vertx.core.impl.EventLoopContext$$Lambda$116.0000000000000000.run(Unknown Source) ~[?:?]
[INFO]  at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163) [netty-common-4.1.34.Final.jar:4.1.34.Final]
[INFO]  at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:404) [netty-common-4.1.34.Final.jar:4.1.34.Final]
[INFO]  at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:495) [netty-transport-4.1.34.Final.jar:4.1.34.Final]
[INFO]  at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:905) [netty-common-4.1.34.Final.jar:4.1.34.Final]
[INFO]  at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) [netty-common-4.1.34.Final.jar:4.1.34.Final]
[INFO]  at java.lang.Thread.run(Thread.java:831) [?:?]
[INFO] Caused by: java.lang.IndexOutOfBoundsException: Index 6 out of bounds for length 6
[INFO]  at jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64) ~[?:?]
[INFO]  at jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70) ~[?:?]
[INFO]  at jdk.internal.util.Preconditions.checkIndex(Preconditions.java:248) ~[?:?]
[INFO]  at java.util.Objects.checkIndex(Objects.java:373) ~[?:?]
[INFO]  at java.util.ArrayList.get(ArrayList.java:425) ~[?:?]
[INFO]  at com.vaadin.flow.data.provider.DataCommunicator.lambda$getJsonItems$3(DataCommunicator.java:615) ~[flow-data-2.1.0.rc2.jar:2.1.0.rc2]
[INFO]  at com.vaadin.flow.data.provider.DataCommunicator$$Lambda$987.0000000000000000.apply(Unknown Source) ~[?:?]
[INFO]  at java.util.stream.IntPipeline$1$1.accept(IntPipeline.java:186) ~[?:?]
[INFO]  at java.util.stream.Streams$RangeIntSpliterator.forEachRemaining(Streams.java:109) ~[?:?]
[INFO]  at java.util.Spliterator$OfInt.forEachRemaining(Spliterator.java:699) ~[?:?]
[INFO]  at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:497) ~[?:?]
[INFO]  at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:487) ~[?:?]
[INFO]  at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913) ~[?:?]
[INFO]  at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:239) ~[?:?]
[INFO]  at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578) ~[?:?]
[INFO]  at com.vaadin.flow.data.provider.DataCommunicator.getJsonItems(DataCommunicator.java:617) ~[flow-data-2.1.0.rc2.jar:2.1.0.rc2]
[INFO]  at com.vaadin.flow.data.provider.DataCommunicator.collectChangesToSend(DataCommunicator.java:560) ~[flow-data-2.1.0.rc2.jar:2.1.0.rc2]
[INFO]  at com.vaadin.flow.data.provider.DataCommunicator.flush(DataCommunicator.java:477) ~[flow-data-2.1.0.rc2.jar:2.1.0.rc2]
[INFO]  at com.vaadin.flow.data.provider.DataCommunicator.lambda$requestFlush$2f364bb9$1(DataCommunicator.java:425) ~[flow-data-2.1.0.rc2.jar:2.1.0.rc2]
[INFO]  at com.vaadin.flow.data.provider.DataCommunicator$$Lambda$556.0000000000000000.accept(Unknown Source) ~[?:?]
[INFO]  at com.vaadin.flow.internal.StateTree.lambda$runExecutionsBeforeClientResponse$1(StateTree.java:368) ~[flow-server-2.1.0.rc2.jar:2.1.0.rc2]
[INFO]  at com.vaadin.flow.internal.StateTree$$Lambda$729.0000000000000000.accept(Unknown Source) ~[?:?]
[INFO]  at java.util.ArrayList.forEach(ArrayList.java:1507) ~[?:?]
[INFO]  at com.vaadin.flow.internal.StateTree.runExecutionsBeforeClientResponse(StateTree.java:365) ~[flow-server-2.1.0.rc2.jar:2.1.0.rc2]
[INFO]  at com.vaadin.flow.server.communication.UidlWriter.encodeChanges(UidlWriter.java:411) ~[flow-server-2.1.0.rc2.jar:2.1.0.rc2]
[INFO]  at com.vaadin.flow.server.communication.UidlWriter.createUidl(UidlWriter.java:187) ~[flow-server-2.1.0.rc2.jar:2.1.0.rc2]
[INFO]  at com.vaadin.flow.server.communication.UidlWriter.createUidl(UidlWriter.java:225) ~[flow-server-2.1.0.rc2.jar:2.1.0.rc2]
[INFO]  at com.vaadin.flow.server.BootstrapHandler$BootstrapPageBuilder.getInitialUidl(BootstrapHandler.java:756) ~[flow-server-2.1.0.rc2.jar:2.1.0.rc2]
[INFO]  at com.vaadin.flow.server.BootstrapHandler$BootstrapPageBuilder.setupDocumentHead(BootstrapHandler.java:739) ~[flow-server-2.1.0.rc2.jar:2.1.0.rc2]
[INFO]  at com.vaadin.flow.server.BootstrapHandler$BootstrapPageBuilder.getBootstrapPage(BootstrapHandler.java:517) ~[flow-server-2.1.0.rc2.jar:2.1.0.rc2]
[INFO]  at com.vaadin.flow.server.BootstrapHandler.synchronizedHandleRequest(BootstrapHandler.java:458) ~[flow-server-2.1.0.rc2.jar:2.1.0.rc2]
[INFO]  at com.vaadin.flow.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:40) ~[flow-server-2.1.0.rc2.jar:2.1.0.rc2]
[INFO]  at com.vaadin.flow.server.VaadinService.handleRequest(VaadinService.java:1540) ~[flow-server-2.1.0.rc2.jar:2.1.0.rc2]

If I use one of the range.length extension functions, then it works fine.

mvysny commented 4 years ago

Yup, please use items.subList(range.start.toInt(), range.endInclusive.toInt()+1) or even simpler items.subList(range.intRange). Please see https://gitlab.com/mvysny/vok-dataloader/blob/master/src/main/kotlin/com/github/mvysny/vokdataloader/ListDataLoader.kt for more details.

jhult commented 4 years ago

Got it. Thank you. I will close this.