12

Recently, I added Detekt analyzer to my application.

After I runned detekt (./gradlew detekt), I got SpreadOperator warning in my main class of application.

Warning on code: runApplication<MessCallsApplication>(*args)

You can read about SpreadOperator warning here: SpreadOperator Warning

my main class:

@SpringBootApplication(exclude = [RedisAutoConfiguration::class])
@EnableCircuitBreaker
@EnableScheduling
class MyApplication {

    companion object : KLogging()
}

fun main(args: Array<String>) {
    Thread.setDefaultUncaughtExceptionHandler { _, exception ->
        MessCallsApplication.logger.error(exception) { "Uncaught exception" }
    }

    runApplication<MessCallsApplication>(*args)
}

Question is, What is the best practice to get rid of from that SpreadOperator warning? Or is it impossible?

Steve Blackwell
  • 5,904
  • 32
  • 49
Seydazimov Nurbol
  • 1,404
  • 3
  • 10
  • 25

5 Answers5

9

In your particular case:

 runApplication<MessCallsApplication>(args = args)

Edit:

This detekt warning is not longer a case: https://github.com/detekt/detekt/pull/3157

However as Klitos Kyriacou mentioned in code - this array is copied (even twice!). Decompiled bytecode:

public final class MessCallsApplicationKt {
   public static final void main(@NotNull String[] args) {
      Intrinsics.checkNotNullParameter(args, "args");
      Schedulers.enableMetrics();
      String[] args$iv = (String[])Arrays.copyOf(args, args.length);
      int $i$f$runApplication = false;
      Intrinsics.checkExpressionValueIsNotNull(SpringApplication.run(MessCallsApplication.class, (String[])Arrays.copyOf(args$iv, args$iv.length)), "SpringApplication.run(T::class.java, *args)");
   }
}
pixel
  • 24,905
  • 36
  • 149
  • 251
  • 1
    Looking at the generated bytecode, I could see that using named parameters also copies the array, the same way as using the spread operator. However, I guess this is something the static code analyser is unaware of and doesn't give you a warning. – Klitos Kyriacou Feb 28 '22 at 15:36
  • Yes, I updated the answer to reflect your findings :) – pixel Mar 01 '22 at 08:46
8

You can add @Suppress("SpreadOperator") before your expression like this:

@SpringBootApplication(exclude = [RedisAutoConfiguration::class])
@EnableCircuitBreaker
@EnableScheduling
class MyApplication {

    companion object : KLogging()
}

fun main(args: Array<String>) {
    Thread.setDefaultUncaughtExceptionHandler { _, exception ->
        MessCallsApplication.logger.error(exception) { "Uncaught exception" }
    }
    @Suppress("SpreadOperator")
    runApplication<MessCallsApplication>(*args)
}
akobor
  • 91
  • 2
  • 2
2

or simply change from:

fun main(args: Array<String>)

to

fun main(vararg args: String)
Jeff Fang
  • 21
  • 1
0

you have to pass the * to the run method:

fun main(vararg args: String) {
  runApplication<RateRefresherApplication>(*args)
}
0

I had this in a function call like this:

private fun combine(vararg messages: String){ . . . }

...

//elsewhere
combine(*messages)

In my particular case, it made sense to change the signature of this to the following (because it was intended to process a vararg from another function, rather than accept a comma-separated list, itself).

This uses with the vararg parameter as an array, rather than converting it into yet another variable argument:

private fun combine(messages: Array<out String>){ . . . }

...

//elsewhere
combine(messages) // now can remove spread operator
gMale
  • 17,147
  • 17
  • 91
  • 116