Home > Software design >  Kotlin (Bug?) Variable changes right after setting it in forEachIndexed
Kotlin (Bug?) Variable changes right after setting it in forEachIndexed

Time:10-21

While writing tests, I encountered a very strange behaviour. I could break it down to the following code snippet:

val random = EasyRandom()
val parametrization = random.nextObject(Parametrization::class.java)
parametrization.ecus.forEachIndexed { index, ecu ->
    ecu.orderNumber = index
    println("index: $index, orderNumber: ${ecu.orderNumber}")
}
println("And again")
parametrization.ecus.forEachIndexed { index, ecu ->
    println("index: $index, orderNumber: ${ecu.orderNumber}")
}

This parametrization variable is randomly set by easy random (https://github.com/j-easy/easy-random) however, this should not have any impact on this case.

Then I set the orderNumber field of each list-entry to the corresponding index and print both the index and the order number (expecting it to be identical)

After that, I print it again without making any change. This is the result:

index: 0, orderNumber: 0
index: 1, orderNumber: 1
index: 2, orderNumber: 2
index: 3, orderNumber: 3
index: 4, orderNumber: 4
And again
index: 0, orderNumber: 0
index: 1, orderNumber: 1
index: 2, orderNumber: 3 // <-- Take a look at this
index: 3, orderNumber: 3
index: 4, orderNumber: 4

So... why exactly did the order number at index 2 change without telling it to? It is always at index 2 and always changing to 3. The class containing orderNumber is a database entity mapped by hibernate. This is the definition:

@Entity
@Table(name = "ecus")
class Ecu(

    // ...

    @Column(name = "order_number", nullable = false, updatable = true)
    var orderNumber: Int,

    // ...
)

CodePudding user response:

Apparently, the problem was actually due to EasyRandom. When generating objects with that dependency, it will reuse objects if data amount gets too large. This lead to the case, that the objects at index 2 and 3 are actualy the same but added to the list twice. Setting a variable to one the object at one index, it will also be changed at the other index because the object is the same. Thanks @Sam for poiting that out.

I have 2 solutions for this problem:

  1. Limit the amount of possible elements for EasyRandom by using val random = EasyRandom(EasyRandomParameters().collectionSizeRange(3, 5)). This might ensure that the data amount will be small enough for EasyRandom to generate only unique objects
  2. Increase the pool size for easy random using val random = EasyRandom(EasyRandomParameters().objectPoolSize(SOME_LARGE_NUMBER). Be careful with this though. Easy Random uses reflection to set the object's variables, which is pretty slow. Generating objects with lists in lists in lists (...) might take ages
  • Related