Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Accessing InjectionPoint inside Spring functional bean definition DSL

We use a Bean factory function to allow injection of Logger objects into our Beans. This looks similar to what Simar Paul Singh describes in his article "Inject loggers in Spring"

import org.slf4j.*
import org.springframework.beans.factory.InjectionPoint
import org.springframework.context.annotation.*

@Bean
@Scope("prototype")
fun logger(injectionPoint: InjectionPoint): Logger {
  return LoggerFactory.getLogger(
      injectionPoint.methodParameter?.containingClass // constructor
          ?: injectionPoint.field?.declaringClass // or field injection
  )
}

Today I attempted to convert this declaration into a Bean declaration using Springs functional bean definition DSL. However I did not succeed to get a hold of the InjectionPoint used to retrieve the class the Logger is injected into.

import org.slf4j.*
import org.springframework.beans.factory.InjectionPoint
import org.springframework.context.support.beans
import org.springframework.context.support.BeanDefinitionDsl.Scope.PROTOTYPE

fun beans() = beans {
    bean(scope = PROTOTYPE) {
        val injectionPoint = ref<InjectionPoint>()
    
        LoggerFactory.getLogger(
            injectionPoint.methodParameter?.containingClass // constructor
                ?: injectionPoint.field?.declaringClass // or field injection
        )
    }
}

The above results in an exception along the lines of:

NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.beans.factory.InjectionPoint' available

Is there a way to retrieve the InjectionPoint or at least the class to provide a behaviour similar to the Bean declaration without DSL?

A minimal reproduction repository can be found on GitHub. Run ./gradlew bootRun or .\gradlew.bat bootRun on Windows to reproduce the error.


I've opened issue #27738 on the GitHub repository of Spring.

like image 830
Endzeit Avatar asked Nov 06 '22 00:11

Endzeit


1 Answers

I don't think you will get an instance of InjectionPoint because it is created in response to the demand a component makes for an injection of a managed bean.

InjectionPoint class is not annotated with @Component or any of its derivatives like @Service. Hence, it is not a managed bean and you will not get a reference using ref<InjectionPoint>.

InjectionPoint only contains meta information about the class or method that is requesting an instance of the managed bean. That is, it not a functional object and hence, not managed. However, it can be optionally accepted by the bean factory method to make some decisions about the instance to be returned. Hence, your bean factory method (whatever it is called in Kotlin) must accept an instance of InjectionPoint, which is what you are doing in your first version in the post.

Also, from the minimal I could understand from the docs of Kotlin Bean DSL here, I couldn't see a way to accept it as a parameter (but that could simply be due to my lack of knowledge of Kotlin. So, in summary, this may not be useful for bean definitions where injection point is needed, unless you can go through the docs and find out a way which I may have missed.

like image 66
Sree Kumar Avatar answered Nov 11 '22 03:11

Sree Kumar