Autowiring a subclass but using parent class as reference - java

Say I have the below class hierarchy:
// Not a component
public class Parent {
}
// See update; this resides in another application context
#Component
public class Child extends Parent {
}
I would like to autowire the Child bean using constructor injection.
#Component
public class Test {
private final Parent parent;
public Test(#Qualifier("child") Parent parent) {
this.parent = parent;
}
}
But Spring is not letting me do this and I get an exception thrown saying:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.foo.Parent' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Qualifier(value=child)}
Is there a way to make this work?
Update
OK, first of all, there is no way you could have come up with an answer to this problem as I made a mistake and did not analyse the situation properly before asking the question.
So what was happening was that the "child" in my case resided in a different application context, which happened to be a bean in the main application context. Because of this reason, what would have been a standard Spring practice, would not have worked for me.
I will post my answer as the solution to this updated scenario.

I think you kinda imitate situation when you try to autowire some class from any outer library. You have to get beans through xml or java config. I think this should work and you should to remove component from Child.
But anyway there should be big reasons to do that. Simple spring autorwiring is more concise and traditional
package com.bssys.ufap.report.springconfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class MyConfig {
#Bean
public Parent getChild() {
return new Child();
}
}

So the solution involved simply looking up the bean from the other application context as follows:
#Component
public class Test {
private final Parent parent;
public Test(ApplicationContext applicationContext) {
this.parent = applicationContext.getBean("anotherContext", ApplicationContext.class).getBean("child", Parent.class);
}
}

Related

Why I should declare bean on constructor?

I have a class ServiceA on project-a:
public class ServiceA {
private ModelA modelA;
public ServiceA(ModelA modelA) {
this.modelA = modelA;
}
}
modelA from other local library (external library). modelA have #Component annotation
when I run this code, cannot found error bean on ModelA. I solve with add #Bean for ModelA on project-a.
Why I should add bean? because the ModelA on external library? Any reference link for I can understand for this case? I want understand for this code. Thank you
The first comment is the most likely answer to your issue;
specifically,
the component scanning that is configured in your project does not include the package that contains the modelA class.

SpringBoot #Autowire why does this example work?

I have created this class:
import org.springframework.stereotype.Component;
...
#Component("notTheNameTestMe") //shouldnt this only work with testMe ?
public class TestMe {
public void showMsg() {
System.out.println("Autowiring works");
}
}
And I'm using it this way in a second class (or better: controller):
import com.example.TestMe; //shouldnt this be not necessary with autowire? But getting error else...
...
#Autowired
private TestMe testMe;
...
this.testMe.showMsg();
But this works perfectly (so maybe Im not really using autowire here?), it even works if I rename the whole TestMe class to TestMeSomething (if I adjust the import in the second class)
I dont really understand what #Autowired does. I thought it just scans for SpringBoot Components (which are named by the string in #Component() and when it finds a match it Injects the dependancy. But in my example the match is impossible and I still can see the message "Autowiring works" in the console. This shouldnt be like this if I would really use autowire here or? What am I understanding in a wrong way? What is the difference to using new TestMe() then? I have the dependancy already with the import or? So not a real dependancy injection, or?
Spring is not operating on the name in the #Component annotation. Rather it's using the name of the class. It's simply finding a class named TestMe because that's the type of the variable you've annotated with #Autowired.

Usage of non public classes in spring java-based config

It seems to be a simple question but yet i couldn't find clear answer while searching documentation and forums. I'm migrating from xml to java-based config (Spring 5.1.9). Due to some legacy restrictions in xml config i need to create a bean from some side library's non public class:
SampleClass.class
package side.library
class SampleClass {
//... some code here
}
context.xml
...
<bean id = "sampleId" class "side.library.SampleClass">
...
And this works fine since Spring uses reflection inside and it creates bean without any problems at compile/runtime, but in java-based config usage of such class leads to an access error:
package my.configuration;
import side.library.SampleClass; // 'side.library.SampleClass' is not public in 'side.library'. Cannot be accessed from outside package
#Configuration
public class JavaConfiguration{
#Bean
public SampleClass sampleClass() {
return new SampleClass(); // same error text
}
}
So, what is the proper way to deal with this sutiation? Using reflection libs in #Configuration class to reach this class seems to be a bad idea.
just a workaround: create a wrapper class in the outer project in the same package and use this class in your configuration.
package com.legacy;
public class Wrapper {
private LegacyImpl legacyImpl;
public Wrapper()
this.legacyImpl = new LegacyImpl();
}
public void wrappedMethod() {
this.legacyImpl.wrappedMethod();
}
}

NoSuchBeanDefinitionException: No qualifying bean of type 'java.util.List<org.springframework.shell.ParameterResolver>'

I'm currently trying to create a Spring Shell Application in Scala.
It works in IntelliJ but does not work when creating the jar.
I have a working proof of concept in Java, that does also successfully create a running jar.
However, my Scala version fails with several:
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'parameterValidationExceptionResultHandler': Unsatisfied dependency expressed through field 'parameterResolvers'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'java.util.List<org.springframework.shell.ParameterResolver>' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
I've tried several minimal examples, moving the classes around (same package) and different Spring annotations (like #SpringBootApplication for both).
Java version:
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
#ShellComponent
public class MyCommands {
#ShellMethod("Add two integers together.")
public int add(int a, int b) {
return a + b;
}
}
Scala Version:
#EnableAutoConfiguration
#ComponentScan
class DemoApplication
object Scark extends App {
SpringApplication.run(classOf[DemoApplication], args:_*)
}
#ShellComponent class MyCommands {
#ShellMethod("Add two integers together.") def add(a: Int, b: Int): Int = a + b
}
I expect to also be able to successfully build a jar from the Scala version.
Edit: I've uploaded the minimal example:
https://github.com/Zethson/Scala-Spring-Shell-Example/tree/feature/minimal_scala_issues_SO
It does not matter at which path you have placed your component(Bean) if you are using component scan first it will check it in current package and then to its sub packages. If your component is placed at different path then include the path in #ComponentScan("Path")
Also make sure to check after applying DEBUG mode in application.properties in java for Spring Boot whether your component is being scanned or not , if not try using #Component just above the component wherever it is , since #SpringBootApplication scans the same while startup.
If I answered incorrectly , do let me know your response and elaborate further.
Happy Coding :)
It seems to be unable to resolve your shell command parameters. Can you try this :
#ShellComponent class MyCommands {
#ShellMethod("Add two integers together.") def add(
#ShellOption(mandatory = true) a: Int,
#ShellOption(mandatory = true) b: Int): Int = a + b
}

Bean interface and Bean implementation in different projects

Is it possible to have a bean interface in a project and the implementation of that bean in another project that includes the previous project as a dependency?
I have the following interface:
package com.proj1.util;
import .....;
public interface Notification {
addNotification();
addError();
}
In the same project (i.e. Proj1) I have also the following class:
package com.proj1.util.exception;
import .....;
public class ExceptionHandler extends RuntimeException ... {
private String errorMessage;
#Override
public void handle() {
Util.getBeanInstance(Notification.class).addError(errorMessage);
}
}
Now in the second project I have the actual implementation of Notification that is as follows:
package com.proj2.beans;
#Named
#ConversationScoped
public class NotificationBean implements Notification, Serializable {
private static final long serialVersionUID = 1L;
...
}
This situation leads to an exception in Tomcat with the message "WebBeans context with scope type annotation #ConversationScoped does not exist within current thread"
My proposal was to add a Factory that produces my NotificationBean but it doesn't seem to change much.
package com.proj2.beans.cdi;
import javax.enterprise.inject.New;
import javax.enterprise.inject.Produces;
import com.proj1.util.Notification;
public class NotificationBeanFactory {
#Produces
public Notification create(#New NotificationBean notificationBean) {
return notificationBean;
}
}
The question is how can I use a bean in a project in which I have only it's interface while the bean implementation is in another project. Is it possible?
The exception suggests there is no running conversation so I would start by determining when do you attempt to use #ConversationScoped bean and from which class.
Your code pieces indicate that ExceptionHandler class calls a magical formula which we do not know anything else about:
Util.getBeanInstance(Notification.class).add(...);
Trying to use this when there is no active conversation might lead to the exception you see. Therefore you could #Inject ExceptionHandler into NotificationBean so that you only ever use it while there is active conversation.
As for the Weld question regarding interface and impl in different projects; it is possible. in your proj2 Weld will simply identify a bean NotificationBean and amongst it's types there will also be Notification hence you can then #Inject Notification.
It might not work the other way round though - in proj1 you cannot #Inject Notification because proj1 itself does not have any bean which would implement that interface.

Categories

Resources