I am facing some problems with kotlin in conjunction with spring.
I have a controller bean (without an interface btw) which has an auto-wired service bean via the primary constructor.
It works perfectly unless I use caching annotations for the controller. Apparently springs caching generates a proxy class under the hood which deals with the caching.
My code looks like this:
#RestController
#RequestMapping("/regions/")
open class RegionController #Autowired constructor(val service: RegionService) {
#RequestMapping("{id}", method = arrayOf(RequestMethod.GET))
#Cacheable(cacheNames = arrayOf("regions"))
fun get(#PathVariable id: Long): RegionResource {
return this.service.get(id)
}
}
The problem now is a null pointer exception when the method is executed, actually this.service is null which technically is not possible as it is a nonnull variable in kotlin.
I assume that class proxies generated by spring initialize the class with null values instead of the autowired bean. This must be a common pitfall using kotlin and spring. How did you circumvent this problem?
In Kotlin both classes and members are final by default.
For the proxying library (CGLIB, javaassist) to be able to proxy a method it has to be declared non final and in a non final class (since those libraries implement proxying by subclassing). Change your controller method to:
#RequestMapping("{id}", method = arrayOf(RequestMethod.GET))
#Cacheable(cacheNames = arrayOf("regions"))
open fun get(#PathVariable id: Long): RegionResource {
return this.service.get(id)
}
You probably see a warning in console regarding RegionController methods not being subject to proxying.
The Kotlin compiler plugin
The Kotlin team has acknowledged this difficulty and created a plugin that marks the standard AOP proxy candidates e.g. #Component with open.
You can enable the plugin by in your build.gradle:
plugins {
id "org.jetbrains.kotlin.plugin.spring" version "1.1.60"
}
Soon this might not be a problem any longer.
There is work in progress that any lib (including spring for example) can specify a list of annotations a file in META-INF. Once a class is annotated with one of these, it will default to open for the class itself and all its functions. This is also true for classes inheriting from an annotated class.
For more details, have a look at https://github.com/Kotlin/KEEP/pull/40#issuecomment-250773204
Related
TLDR: I need an interface/abstract class and all classes implementing it to have access to a Spring managed bean. Can Spring inject a bean into an interface/abstract-class and its subclasses simply via #Autowired ?
I am working on an API built with Spring Webflux + Cloud Gateway that depending on the cookie JWT authorized party, identifies the User's policy group and assign an Attribute ENUM "InterfaceID" to the ServerWebExchange via exchange.getAttribute().put("InterfaceID",InterfaceID.A) after the JWT is validated, and currently uses "InterfaceID" to represent the different groups of users/different interface the user entered from.
JWTValidationFilter.java [Current]
switch(JWTValidator.validate(jwt).get("AZP")){
//if user is from company A or its partners
case "a":
case "aa":
exchange.getAttribute().put(InterfaceID.COMPANY_A_ACCESS);
break;
case "b":
exchange.getAttribute().put(InterfaceID.NORMAL_ACCESS);
...
}
For certain API endpoints (say /api/getSessionDocument), different "InterfaceID" fetches data from different DB/apis, as well as have different permission checking on top of that.
RequestController.java [Current]
#Autowired
APICallerUtil apiCallerUtil;
switch(exchange.getAttribute.get(InterfaceID)){
case "NORMAL_ACCESS":
apiCallerUtil.getDataFromApiA();
break;
case "COMPANY_A_ACCESS":
// call api B but check for permission from api D first
...
}
The endpoint's controller now has another switch statement, and to many code analyzers this have been a code smell. I have been trying to refactor this entire bit of code to use polymorphism to handle the different "getSessionDocument" flows, but i run into issues regarding the injection of util classes that calls specific APIs.
APICallerUtil.java class, exisiting class from the project, would prefer not to refactor this.
#Component
public class APICallerUtil{
#Value("${some uri to some API}") //different by environment and therefore cant be static final
private String uri1;
#Value("${some auth to some API}") //confidential
private String uri1AuthHeader;
//...
public JSONObject getDataFromApiA(String somekey){ //cant be static since uri1 is not static
//Some code that uses uri1 and apache httpclient
return data;
}
...
}
IBaseAccess.java
interface IBaseAccess{
default Mono<JSONObject> getSesssionDocument(ServerWebExchange e){return Mono.error("not implemented");}
}
RequestController.java [new]
#Autowired
APICallerUtil apiCallerUtil;
return exchange.getAttribute.get(InterfaceID).getSessionDocument(exchange);
NormalAccess.java
public class NormalAccess implements IBaseAccess{
//can i autowire APICallerUtil here?
//use constructor to pass the Util class reference here?
Mono<JSONObject> getSesssionDocument(ServerWebExchange e){
//need to call ApiA here
//need to call ApiC here
}
}
NormalAccess needs to call APICaller.getDataFromApiA(), but it needs a reference to the Spring managed instance of APICaller. What would be the "correct" way to pass the reference/autowire API caller into NormalAccess, or even better IBaseAccess (so that the implementing classes can use the Util bean)?
JWTValidationFilter.java [new]
switch(JWTValidator.validate(jwt).get("AZP")){
//if user is from company A or its partners
case "a":
case "aa":
exchange.getAttribute().put("InterfaceID",new CompanyAAccess(/*pass the util class here?*/));
break;
case "b":
exchange.getAttribute().put("InterfaceID",new NormalAccess(/*pass the util class here?*/));
...
}
I have tried several methods, but either I lack the knowledge on the specific Spring feature, or that method is deeemed a bad design choice by some, including:
Making the methods and fields in APICallerUtil static, via suggestions from Spring: How to inject a value to static field? and Assigning private static final field member using spring injection , then the Access classes can call the static methods.
Creating a contructor for IBaseAccess that consumes the APICallerUtil reference and store it inside. The JWTfilter would hold an autowired APICallerUtil and pass it in when the attribute is assigned.
Create a static class that provides the application context and Access classes use applicationContext.getBean("APICallerUtil"); to obtain the bean.
Use the #Configurable annotation? I could not find much documentation on how this works for interfaces/abstract-class.
I understand that there might not exist an absolute answer for this question, but regardless I'd like suggestion/feedback on which of these approaches are viable/good. Especailly concerning whether the APIUtil class should be static or not.
I have the following repository implementation in Kotlin:
#Repository
class SapArticleRepository(jooqDsl: DSLContext, jooqConfiguration: DefaultConfiguration) :
AbstractSapRepository<TrmSapArticleRecord, TrmSapArticlePojo>(jooqDsl, jooqConfiguration)
with the following base class:
abstract class AbstractSapRepository<R : UpdatableRecord<R?>, TPojo>(
var dao: DAOImpl<R, TPojo, Long>,
jooqDsl: DSLContext,
jooqConfiguration: DefaultConfiguration,
) {
fun findById(id: Long) = dao.findById(id)
}
When running an Integration test, I get an exception, because dao is null. I checked (by debugging): dao is not null when the constructor is called, but it indeed is when findById is called. I noticed that the object references are not the same (because of CGLIB, the Spring proxy), but I don't know what happens between the constructor call and the time the proxied bean is created.
I tried an abstract function getDaoImpl() an which is implemented in SapArticleRepository (returning the object instance) and the calling that method (instead of accessing dao), but that seems overly complicated. There must be a way to pass the constructor argument/field in a way so it is still present by the time the Bean is used.
Note. TrmSapArticleDao is just a Jooq-generated class.
Edit: I already found Constructor-Injected field is null in Spring CGLIB enhanced bean, but the accepted answer does not seem to answer my question.
As always, I found the solution 5 minutes after posting the question...
The problem was that fields passed in the constructor are final in Kotlin by default. CGLIB can't intercept final fields/method and therefore leaves them initialized with null (see this answer on GitHub.
The solution is to make the constructor field open. So above code works when defining the constructor of the abstract class as follows:
abstract class AbstractSapRepository<R : UpdatableRecord<R?>, TPojo>(
open var dao: DAOImpl<R, TPojo, Long>,
jooqDsl: DSLContext,
jooqConfiguration: DefaultConfiguration,
)
I have a straightforward test case. I have a controller which has a parameter of a type Spring doesn't support by default, so I wrote a custom resolver.
I create the mock mvc instance I'm using like so:
mvc = MockMvcBuilders.standaloneSetup(controller).setCustomArgumentResolvers(new GoogleOAuthUserResolver()).build();
However, Spring is also registering almost 30 other argument resolvers, one of which is general enough that it is getting used to resolve the argument before mine. How can I set or sort the resolvers so that mine is invoked first?
This worked for me without reflection:
#RequiredArgsConstructor
#Configuration
public class CustomerNumberArgumentResolverRegistration {
private final RequestMappingHandlerAdapter requestMappingHandlerAdapter;
#PostConstruct
public void prioritizeCustomArgumentResolver () {
final List<HandlerMethodArgumentResolver> argumentResolvers = new ArrayList<>(Objects.requireNonNull(requestMappingHandlerAdapter.getArgumentResolvers()));
argumentResolvers.add(0, new CustomerNumberArgumentResolver());
requestMappingHandlerAdapter.setArgumentResolvers(argumentResolvers);
}
}
The issue was that the People class the Google OAuth library I am using extends Map and the mock servlet API provides no way to manipulate the order in which the handlers are registered.
I ended up using reflection to reach into the mocks guts and remove the offending handler.
I am looking for a way to store my object and it seems that the best approach is to use proxies. I found 2 annotation in the internet, which one should I use :
#Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES)
or
#Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS )
Moreover, is it true that the proxies is the best way to use than using #Component
#Scope("session") or using #SessionAttributes?
You'll need to understand what each of those annotations does to choose for yourself. See the javadoc, here. Continue for a more detailed explanation.
The first
#Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES)
creates
a JDK dynamic proxy implementing all interfaces exposed by the class of the target object
In other words, the proxy will be a subtype of the interfaces that the target object's class implements, but won't be a subclass of the target object's class itself.
Essentially Spring does the following
public class Example {
public static void main(String[] args) throws Exception {
Foo target = new Foo();
InvocationHandler proxyHandler = ... // some proxy specific logic, likely referencing the `target`
// works fine
Printable proxy = (Printable) Proxy.newProxyInstance(Example.class.getClassLoader(),
target.getClass().getInterfaces(), proxyHandler);
// not possible, ClassCastException
Foo foo = (Foo) proxy;
}
public static class Foo implements Printable {
#Override
public void print() {
}
}
public interface Printable {
void print();
}
}
The proxy returned won't be of type Foo and you therefore can't inject it into any targets of that type. For example, Spring will fail to inject it into a field like
#Autowired
private Foo foo;
but will successfully inject the proxy into a field like
#Autowired
private Printable printable;
All calls to the proxy will be handled by the InvocationHandler (which usually performs some use case specific logic then delegates to the target object).
The second annotation
#Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS )
creates
a class-based proxy (uses CGLIB).
In addition to interfaces, with CGLIB Spring will be able to create a proxy whose class is a subclass of the target's class. In essence, it does the following
Foo target = new Foo();
net.sf.cglib.proxy.Enhancer enhancer = new net.sf.cglib.proxy.Enhancer();
enhancer.setInterfaces(target.getClass().getInterfaces());
enhancer.setSuperclass(target.getClass());
net.sf.cglib.proxy.MethodInterceptor interceptor = ... // some proxy specific logic, likely referencing the `target`
enhancer.setCallback(interceptor);
// works fine
Foo proxy = (Foo) enhancer.create();
CGLIB creates a new class that is a subclass of Foo and instantiates it (invoking the constructor of Foo). All calls to the proxy will be intercepted by the provided callback (which usually performs some use case specific logic and then delegates to the target object).
Since the proxy class extends Foo, Spring can inject the proxy into a field (or constructor/method parameter) like
#Autowired
private Foo injectMe;
All this to say, if you're programming to interfaces, then ScopedProxyMode.INTERFACES will be sufficient. If you're not, then use ScopedProxyMode.TARGET_CLASS.
As for using #SessionAttributes, it is not an alternative to session scoped beans. Session attributes are just objects, they are not beans. They don't possess the full lifecycle, injection capabilities, proxying behavior that a bean may have.
If you want to store the whole bean in the session, use #Scope, otherwise use #SessionAttributes. In the case of using #Scope, if the class implements some interfaces then use INTERFACES proxy mode, if not use TARGET_CLASS.
Usually your service implements an interface, which allows the use of JDK proxies (INTERFACES mode). But if that is not the case then use TARGET_CLASS, which creates a CGLIB proxy.
Using INTERFACES should be used if possible and TARGET as last resort if the bean does not implement interfaces.
While going through a blog post provided in the comments above, I found a comment stating cons of interface-based proxies.
On the post, user Flemming Jønsson posted this:
Be careful with using interface-based proxies.
If you are using Spring Security or Spring Transactions you might experience oddities when using interface-based proxies.
E.g. if you have a bean T and that bean has methods a() and b() that are both annotated transactional. Calls from other beans directly to a() or b() will behave properly (as configured). However if you introduce an internal call - where a() calls b() then b's transactional metadata will have no effect. The reason is that when you are using interface-based proxies the internal call will not go through the proxy - and thus the transactional interceptor will not have a chance to start a new transaction.
The same goes for Security. If method a() only requires USER-role but calls b() that requires ADMIN-role, then the internal call from a to b will be performed for any USER with no warnings. Same reason as above, internal calls do not go through the proxy and thus the security interceptor does not have a chance to act upon the call to b() from a().
To solve issues like these use targetClass.
I have a Grails application that needs to run a strategy that will likely be swapped out over time. I know Spring underlies Grails, so I was wondering if I had access to Spring's IoC container so that I could externalize the actual dependency in an xml file (note: I have never actually done this, but just know of it, so I may be missing something). My goal is to be able to do something like the following:
class SchemaUpdateService {
public int calculateSomething(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
IStrategy strat = (IStrategy) ctx.getBean("mystrat");
}
}
And then map the appropriate implementation in the beans.xml file. I assume this is supported in Grails. Does anyone have any documentation on how this would work? Do I really just need the Spring IoC library and it will just work? Thanks!
You define your beans in resources.xml or resources.groovy. The grails documentation is very clear about how to access the Spring application context.
You can access the application context from any Grails artefact using
ApplicationContext ctx = grailsApplication.mainContext
You can then use this to retrieve whichever beans you're interested in:
IStrategy strat = (IStrategy) ctx.getBean("mystrat")
In classes that don't have access to grailsApplication, you could use a helper such as the following to access the application context and the beans therein
class SpringUtils {
static getBean(String name) {
applicationContext.getBean(name)
}
static <T> T getBean(String name, Class<T> requiredType) {
applicationContext.getBean(name, requiredType)
}
static ApplicationContext getApplicationContext() {
ApplicationHolder.application.mainContext
}
}
However, this should only be necessary if you need to retrieve different implementations of the same bean at runtime. If the required bean is known at compile-time, just wire the beans together in resources.xml or resources.groovy
First of all, you want to define your strategy in your grails-app/conf/spring/resources.groovy:
beans = {
myStrat(com.yourcompany.StrategyImpl) {
someProperty = someValue
}
}
Then, you simply def the a property with the same name into your service:
class SomeGrailsService {
def myStrat
def someMethod() {
return myStrat.doSomething()
}
}
In any Grails artefact (such as services and domain classes), Grails will automatically give the myStrat property the correct value. But don't forget, in a unit test you'll have to give it a value manually as the auto-wiring does not happen in unit tests.
Outside of a Grails artefact, you can use something like:
def myStrat = ApplicationHolder.application.mainContext.myStrat
In Grails 2.0, Graeme et al are deprecating the use of the *Holder classes (such as ApplicationHolder and ConfigurationHolder), so I'm not quite sure what the Grails 2.0 approach would be...