3

Taking into account the following example where I'm trying to use the Sample configuration bean within SampleStarter to start the service with the bean properly filled. The .scala file has SampleStarter.scala as name, with Sample being defined within that exact same file.

@SpringBootApplication
@Service
object SampleStarter {

  @(Autowired @setter)
  var sample: Sample = _ // always null, @Autowired not working?

  def getInstance() = this

  def main(args: Array[String]): Unit = {
    SpringApplication.run(classOf[Sample], args: _*)

    sample.run()
  }

}

@Configuration
@ConfigurationProperties("sample")
@EnableConfigurationProperties
class Sample {

  @BeanProperty
  var myProperty: String = _

  def run(): Unit = { // bean config seems OK, when debugging with @PostConstruct the 'myProperty' value is filled properly
    print(myProperty)
  }

}

Whenever I hit sample.run() after SpringApplication.run(classOf[Sample], args: _*), sample property is always null. I reckon this has something to do with object in Scala since all their members are static AFAIK. I took this SO question How to use Spring Autowired (or manually wired) in Scala object? as inspiration but still can't make my code to work.

Is there something wrong the way I'm instantiating the classes or is it something related to Scala?

EDIT

Following @Rob's answer, this is what I did trying to replicate his solution.

@SpringBootApplication
@Service
object SampleStarter {

  @(Autowired @setter)
  var sample: Sample = _

  def getInstance() = this

  def main(args: Array[String]): Unit = {
    SpringApplication.run(classOf[Sample], args: _*)

    sample.run()
  }

}


@Configuration // declares this class a source of beans
@ConfigurationProperties("sample") // picks up from various config locations
@EnableConfigurationProperties // not certain this is necessary
class AppConfiguration {

  @BeanProperty
  var myProperty: String = _

  @Bean
  // Error -> Parameter 0 of constructor in myproject.impl.Sample required a bean of type 'java.lang.String' that could not be found.
  def sample: Sample = new Sample(myProperty)

}

class Sample(@BeanProperty var myProperty: String) {

  def run(): Unit = {
    print(myProperty)
  }

}
czr_RR
  • 541
  • 5
  • 16

1 Answers1

2

@Configuration declares a source file that is capable of providing @Beans. This is not what you want. You want/need to have Sample as a POJO class (POSO?) and then have another class "AppConfiguration" (say) annotated with @Configuration that creates an @Bean of type Sample

My scala is very rusty so this may not compile at all but the structure should be roughly correct.

@Configuration // declares this class a source of beans
@ConfigurationProperties("sample") // picks up from various config locations
@EnableConfigurationProperties // not certain this is necessary
class AppConfiguration {

  @Bean
  def getSample(@BeanProperty myProperty: String): Sample = new Sample(myProperty)

}
class Sample {

  var myProperty: String

  def Sample(property : String) = {
    this.myProperty = myProperty
  }

  def run(): Unit = {
    print(myProperty)
  }
}

Now you have a Sample class as an @Bean and it can be @Autowired in where ever necessary.

@SpringBootApplication
@Service
object SampleStarter {

  // note its typically better to inject variables into a constructor
  // rather than directly into fields as the behaviour is more predictable
  @Autowired
  var sample: Sample

  def getInstance() = this // not required ??

  def main(args: Array[String]): Unit = {
    SpringApplication.run(classOf[Sample], args: _*)

    sample.run()
  }
}

FWIW, you can start the SpringBoot application independently and have the logic for @Service entirely separate. An @Service is another type of @Bean and is made available to the rest of the SpringBootApplication.

Rob Evans
  • 2,822
  • 1
  • 9
  • 15
  • Thanks a lot for replying Rob! Got my doubts crystal clear with the @Configuration and @Service! However, I'm struggling to load the bean since it will complain with "Parameter 0 of constructor in myproject.impl.Sample required a bean of type 'java.lang.String' that could not be found." Will update the first post with some modifications I did trying to make it work. – czr_RR Oct 15 '20 at 12:41