IntelliJ can't find Spring bean from Kotlin object - spring

I have a Spring Boot 2 + Kotlin application opened with IntelliJ 2019.1.
In this application I annotate some Kotlin objects with #Component. Example:
#Component
object MyObject: MyInterface {
// code
}
I have many different implementation of MyInterface (all with Kotlin objects) and I want to inject all of them in a list in another bean. Example:
#Component
class MyComponent #Autowired constructor(private val objects: List<MyInterface>) {
// code
}
The code runs correctly (the beans are inject in the list objects) but IntelliJ shows an error saying:
Could not autowire. No beans of '? extends MyInterface' or 'List<? extends MyInterface>' types found.
If I change 'object' to 'class' at 'MyObject', the error disappears.
My questions are:
Is it a problem with IntelliJ?
Is it not recommended to annotate Kotlin objects with #Component?

For information, as a possible workaround while the ticket created by Николай in this answer is not treated, I'm ignoring the error/warning only where I need with #Suppress("SpringJavaInjectionPointsAutowiringInspection"). Example:
#Suppress("SpringJavaInjectionPointsAutowiringInspection")
#Autowired
private lateinit var kotlinObjectBeans: List<MyInterface>
I hope it can help others that don't want to disable this check elsewhere.

I would recommend not to use kotlin objects with #Component or any other bean annotation.
There are two aspects and heaving a mix of them leads to lots of problems:
It might be several ApplicationContext instances in your application.
Kotlin object is related to a specific ClassLoader

It is a little bit strange to use Kotlin objects as #Component-s, because if your class knows that it will be used inside Spring-container you'll get more flexibility if you delegate to Spring the decision should this class be a singleton or not and all the other lifecycle management.
But practically I don't see any reason why it could be "not recommended" if you know what you are doing, and aware of probably bugs if your object become stateful.
So I think IDEA should support your case, and I've filled up a ticket IDEA-211826

Related

How to make a bean discoverable by Quarkus CDI without using annotations

I have a simple Quarkus resource:
#Path("/rosters")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class RosterResource {
private final RosterService rosterService;
public RosterResource(RosterService rosterService){
this.rosterService = rosterService;
}
#GET
#Path("/{rosterId}")
public Response getRoster(#PathParam("rosterId")Long rosterId){
return Response.ok(rosterService.getRosterById(rosterId)).build();
}
}
I am trying to inject the RosterServiceinstance in my resource, but I am getting a javax.enterprise.inject.UnsatisfiedResolutionException. However, if I use the #ApplicationScoped annotation on RosterService, then everything works just fine. Is there a way of injecting the RosterService class in my resource without using annotations? In other words, is there a way of making RosterService discoverable by the Quarkus container without directly annotating the class?
Edit: looking into the CDI docs, it seems that you can manually register beans using a method with a #BuildStep annotation. However, it is not clear to me which class should contain the annotated method)
Another option would be to use a Jandex index
To the best of my knowledge, Quarkus only implements so called annotated bean discovery. That means that all CDI beans in Quarkus have to have a bean defining annotation. #ApplicationScoped is one of them.
EDIT: regarding a Jandex index, that allows you to scan for beans in additional JARs. In other words, it will only expand the set of classes that are scanned for a bean defining annotation.
When it comes to a #BuildStep method -- that is only possible in a Quarkus extension. Extensions are powerful (and indeed they can define additional beans) but also complex. You can start at https://quarkus.io/guides/building-my-first-extension, but it may feel overwhelming. It may also feel like this is not the right thing to do if you want to just make your class a bean -- and that would be true. But if your class comes from an external library that you can't change, extension makes sense.
Is there a specific reason why you don't want to annotate your service class with #ApplicationScoped (or any other of the bean discover/scope annotations)?
The only other way that I'm aware of (instead of annotations) is - as you yourself mentioned - the use of Jandex index.

Spring Context Test With Just One Bean

What's the recommended way to run a spring boot test where only the one subject under test is configured in the context.
If I annotate the test with
#RunWith(SpringRunner.class)
#SpringBootTest(properties = "spring.profiles.active=test")
#ContextConfiguration(classes = MyTestBean.class)
Then it seems to work - the test passes, the context starts quickly and seems to only contain the bean that I want. However, this seems like an incorrect use of the #ContextConfiguration(classes = MyTestBean.class) annotation. If I understand correctly the class that I reference is supposed to be a Configuration class, not a regular spring service bean or component for example.
Is that right? Or is this indeed a valid way to achieve this goal? I know there are more complex examples like org.springframework.boot.test.autoconfigure.json.JsonTest which use #TypeExcludeFilters(JsonExcludeFilter.class) to control the context - but this seems overkill for my use case. I just want a context with my one bean.
Clarification
I know that I can just construct the one bean I am testing as a POJO without a spring context test and remove the three annotations above. But in my precise use case I am actually reliant on some of the configuration applied to the context by settings in the application-test.properties file - which is why I've made this a Spring Boot test with a profile set. From my perspective this isn't a plain unit test of a single class in isolation of the spring context configuration - the test is reliant on certain configuration being applied (which is currently provided by the spring boot app properties). I can indeed just test the components as a POJO by creating a new instance outside of a spring context, I'm using constructor injection making the providing of necessary dependencies simple but the test does rely on things like the log level (the test actually makes assertions on certain logs being produced) which requires that the log level is set correctly (which is currently being done via logging.level.com.example=DEBUG in a properties file which sets up the spring context).
For starters, reading the documentation first (e.g., the JavaDoc linked below in this answer) is a recommend best practice since it already answers your question.
If I understand correctly the class that I reference is supposed to be
a Configuration class, not a regular spring service bean or
component for example.
Is that right?
No, that's not completely correct.
Classes provided to #ContextConfiguration are typically #Configuration classes, but that is not required.
Here is an excerpt from the JavaDoc for #ContextConfiguration:
Annotated Classes
The term annotated class can refer to any of the following.
A class annotated with #Configuration
A component (i.e., a class annotated with #Component, #Service, #Repository, etc.)
A JSR-330 compliant class that is annotated with javax.inject annotations
Any other class that contains #Bean-methods
Thus you can pass any "annotated class" to #ContextConfiguration.
Or is this indeed a valid way to achieve this goal?
It is in fact a valid way to achieve that goal; however, it is also a bit unusual to load an ApplicationContext that contains a single user bean.
Regards,
Sam (author of the Spring TestContext Framework)
It is definitely a reasonable and normal thing to only test a single class in a unit test.
There is no problem including just one single bean in your test context. Really, a #Configuration is (typically) just a collection of beans. You could hypothetically create a #Configuration class just with MyTestBean, but that would really be unnecessary, as you can accomplish doing the same thing listing your contextual beans with #ContextConfiguration#classes.
However, I do want to point out that for only testing a single bean in a true unit test, best practice ideally leans towards setting up the bean via the constructor and testing the class that way. This is a key reason why the Spring guys recommend using constructor vs. property injection. See the section entitled Constructor-based or setter-based DI of this article, Oliver Gierke's comment (i.e. head of Spring Data project), and google for more information. This is probably the reason you're getting a weird feeling about setting up the context for the one bean!
You can also use ApplicationContextRunner to create your context using a test configuration of your choice (even with one bean if you like, but as other people have already mentioned for one bean it's more reasonable to use the constructor the classical way without using any spring magic).
What I like this way of testing is the fact that test run very fast since you don't load all the context. This method is best used when the tested bean doesn't have any Autowired dependencies otherwise it's more convenient to use #SpringBootTest.
Below is an example that illustrates the way you can use it to achieve your goal:
class MyTest {
#Test
void test_configuration_should_contains_my_bean() {
new ApplicationContextRunner()
.withUserConfiguration(TestConfiguration.class)
.run(context -> {
assertThat(context.getBean(MyTestBean.class)).isNotNull();
});
}
#Configuraiton
public static class TestConfiguration {
#Bean
public MyTestBean myTestBean(){
new MyTestBean();
}
}
}

Spring injects dependencies in constructor without #Autowired annotation

I'm experimenting with examples from this official Spring tutorials and there is a dependency on this code:
https://github.com/spring-guides/gs-async-method/tree/master/complete
If you look at the code on AppRunner.java class, I have 2 questions:
When server is starting, if I put a breakpoint in this class's constructor, seems like in the constructor, the GitHubLookupService is provided by spring, using the #Service bean that was configured. BUT, there was no #Autowired annotation on the constructor, so how in the world this constructor get called with the right dependency? It was supposed to be null.
Is it an automatic assumption of Spring Boot?
Does Spring see "private field + constructor argument, and it assumes it should look for an appropriate bean?
Is it Spring Framework or Spring boot?
Am I missing something?
As I remember, it was mendatory to provide default constructor to beans / service etc. How come this class (AppRunner) doesn't have a default constructor?
How does Spring knows that it should run the constructor with the argument?
Is it because it is the only constructor?
Starting with Spring 4.3, if a class, which is configured as a Spring bean, has only one constructor, the #Autowired annotation can be omitted and Spring will use that constructor and inject all necessary dependencies.
Regarding the default constructor: You either need the default constructor, a constructor with the #Autowired annotation when you have multiple constructors, or only one constructor in your class with or without the #Autowired annotation.
Read the #Autowired chapter from the official Spring documentation for more information.
Think of it this way... Suppose you have the following component:
#Component
public class FooService {
public FooService(Bar bar) { /*whatever*/ }
}
When Spring is scanning this class, it wants to know how it should go about constructing an instance. It's using reflection so it can get a list of all of the constructors at runtime.
In this case, it is completely unambiguous how Spring must construct this instance. There's only one constructor so there is no decision to be made, and no ambiguity at all.
If you add #Autowired here, you are not narrowing anything down, and you are not giving Spring any extra information to help make its decision - its decision is already made because there is only one candidate.
And so, as a convenience, the Spring team decided #Autowired should be optional. Since its not helping the Spring framework to make a decision, its presence is just noise.
If your component has multiple constructors then you can use #Autowired on one of them to tell Spring "use this one, not that one".

Spring fallback bean implementation

I'm currently trying to configure Spring Boot (using Java Annotations and ComponentScan) for the following scenario:
Scenario
There's an interface MyService.
I want to provide a default implementation for MyService, let's call it MyDefaultService.
If the component scan detects no other implementation for MyService, Spring should instantiate MyDefaultService as a "fallback".
If there is a different implementation of MyService present, let's say MyCustomService, then that bean should always take precedence over MyDefaultService when autowiring a dependency to MyService. In that regard, MyDefaultService should be recessive (as opposed to #Primary).
Ideally, there should not need to be an additional annotation on MyCustomService to have it "override" MyDefaultService.
Ideally, no explicitly implemented factories or factory methods should be required.
Question
The question is: how do I need to annotate the MyDefaultService class in order to achieve this?
What I tried so far to solve the problem
Annotating MyDefaultService with #ConditionalOnMissingBean(MyService.class). Didn't work because MyDefaultService is never used, even if there is no other implementation of MyService.
There is an annotation called #Primarythat solves the problem. However, it needs to reside on MyCustomService, a class that I try to keep free of additional annotations. Essentially, I need the inverse annotation of #Primary on MyDefaultService. However, I couldn't find such an annotation.
Concrete use case
I am developing a service layer in one project, and a different project will implement a web UI layer on top of it. The UI project has a dependency to the service layer project. However, for certain functionalities implemented at the service layer, I need to know which user is currently logged in at the web context. So I have to define a service interface for that in the service layer project, such that it can be implemented by the UI project. However, for testing purposes in the service-layer project, I need a default implementation of that interface. Also, in case that the UI project team forgets to implement this interface, the app should not crash, but instead instantiate the fallback bean and issue a warning.
Thanks & kind regards,
Alan
I suggest writing an implementation of FactoryBean to do this. Your FactoryBean would scan the bean factory looking for beans that implement MyService, and if it finds one it returns that bean from getObject. If it doesn't, then it can instantiate MyDefaultService directly and return that. Your factory bean then gets annotated with #Primary.
So pieces like this (pseudo-code):
public class MyServiceFactory implements FactoryBean<MyService> {
ListableBeanFactory beanFactory;
public MyService getObject() {
Map beans = beanFactory.getBeansOfType(MyService.class)
if (beans.isEmpty())
return new MyDefaultService(); // plus args, obviously
else
return get_some_bean_from_the_map
}
}
and then
#Primary
#Bean
public MyServiceFactory MyServiceFactory() {
return new MyServiceFactory();
}
Spring will automatically handle the factory bean (i.e. it will make the MyService object available as a bean for injection like normal.
This solution doesn't require any special magic, and it's fairly obvious how it works. You can also handle errant cases such as multiple MyService beans being declared.

Spring3 deserialization - singleton injection

i am developing a Webapplication with JSF2 and Spring3 and have a problem with deserialization.
I have some session-scoped beans defined like so:
#Controller(value = "admin")
#Scope(value = "session")
public class AdminBean implements Serializable {
...
also i have some singletons defined like so:
#Repository
public class Repo {
Singletons are injected into the session-beans like this
#Resource
private transient Repo repo;
After i added transient, my problems with serialization/deserialization went away. But now i have the problem that after deserialzing the dependencies (repo in this case) are null. I searched a lot on this problem and found some workarounds, but i still wonder what the best solution for this problem is?
It seems to me that using application-scoped beans in session-beans is a quite common case, isn't there a clean solution for this? I came arround a solution with #Configurable, but do i really need some load-time-weaving stuff? The targets of the injection are already spring-managed, so it doesn't make sense to me..
Please enlight me
update 2 years later: You CAN transparently inject session-scoped beans into application-scoped-beans (might not be a good idea in most cases though). I just had to set the proxyMode on #Scope accordingly.
Try getting AutowireCapableBeanFactory through applicationContext.getAutowireCapableBeanFactory() and there are some methods like autowireBeanProperties, autowireBean and configureBean that should be able to reconfigure your ban after deserialization. Choose a method best for you (one of them triggers post processing, others not etc..)
Second idea is to wrap Repo in a proxy, that is serializable. It'll serialize with AdminBean and deserialize. This proxy should hold 'real' transient reference and if it gets null after deserialization, it should lookup it from the Application Context.
I heard that Spring 3 automaticaly wraps beans with such a proxy, but I've never managed to make it work.
I faced similar problem using #ViewScoped of JSF where backing bean has to serializable which in turn wants all dependencies to be serializable, which in all scenarios is not possible to get all. As #Peter mentioned about Spring 3 have a look at link # stackoverflow discussing same here. I used transient for some dependencies(Spring) and for deserialization process I hooked bean to
private void writeObject(java.io.ObjectOutputStream stream)
and private void readObject(java.io.ObjectInputStream stream)
in view scoped bean and tweaked them to get proper reference.

Resources