Abstract classes, interfaces and Autowired - java

I have the following main class:
public class Startup implements UncaughtExceptionHandler {
#Autowired
private MessageListener messageListener;
private static Startup startup;
public static void main(String[] args) {
Startup start = new Startup();
start.init(args);
}
public void init(String[] args) {
context = new ClassPathXmlApplicationContext("applicationContext.xml");
startup = (Startup) context.getBean( "startup" );
startup.start(); //here the messageListener is used
}
// here goes the main class that calls the method where messageListener is used
}
#Component
public class ProdMessageListener
extends AbstractMessageListener implements MessageListener {...}
and
public abstract class AbstractMessageListener
implements MessageListener {...}
as well as
#Component
public interface MessageListener extends QueueAware {...}
#Component
public interface QueueAware {...}
My Spring context uses to locate all the classes and interfaces.
However the bean is not recognized and I get:
No qualifying bean of type
[com.ware.messaging.listener.MessageListener] found for
dependency.
Any ideas why autowiring does not work?

Just make sure you have added your base package to the spring context configuration like below to allow spring to load all the components into the container
<context:component-scan base-package="pakage1.package2"/>

Do you know what the problem was? Spring does not seem to autowire static fields. Now everything works.

Related

Autowired property is null in EnvironmentPostProcessor implementation class on startup

In my SpringBoot app, I have Autowired an configObject in the class that implements EnvironmentPostProcessor.
The injected class reads data from a different source on startup as this is required for the app to work.
But upon starting the application, the configObject is coming off as Null.
#SpringBootApplication
#EnableEncryptableProperties
#EnableConfigurationProperties
#EnableCaching
#Slf4j
public class SBApplication {
public static void main(String[] args) {
SpringApplication.run(SBApplication.class, args);
}
}
And the AppEnvironmentPostProcessor class where the Autowired object is called. This class is configured as org.springframework.boot.env.EnvironmentPostProcessor in spring.factories. The class gets called on start up.
#Slf4j
public class AppEnvironmentPostProcessor implements
EnvironmentPostProcessor, Ordered {
#Autowired
KeysConfig keysConfig;
#Override
public void postProcessEnvironment(ConfigurableEnvironment environment,
SpringApplication application) {
// keysConfig is null
String key = keysConfig.getSecretKeyMap().get("key12");
}
}
And in the KeysConfig class
#Component
public final class KeysConfig {
public Map getSecretKeyMap() {
//Returns key map
}
}
I am using Intellij Ultimate. How can I debug and resolve this?
EnvironmentPostProcessors are created before the application context has been created and, therefore, before dependency injection is possible. This means that #Autowired won’t work.
You’ll have to update your implementation to create an instance of KeysConfig itself, or to use a different approach that mimics whatever KeysConfig currently does.

Spring Boot not recognizing Interface

I have an interface like so:
public interface Animal {
void setName(String animal);
String getName();
}
and I have a Class that implements the interface:
#Component
public class Dog implements Animal {
private String name;
public void setName(String name) {
this.name= name;
}
public String getName() {
return this.name;
}
}
In another class (ProcessAnimal), I AutoWire the interface:
public class ProcessAnimal {
#Autowired
public Animal animal;
public void processAnimals() {
animal.setName("Fido");
}
}
I only have one class that implements Animal so this should work, however, I get a NullPointerException when it hits the animal.setName("Fido"); line. IntelliJ is complaining that Autowired members must be defined in valid Spring bean (#Component|#Service...) which I have... I don't understand what I'm doing wrong. I've tried to add a #Qualifier, but still it didn't work and it shouldn't be necessary since I only have one implementation.
-java
-com.example.com.AnimalProcessing
-Animal
-Animal.java
-Dog.java
-ProcessAnimal.java
-AnimalProcessingApplication.java
AnimalProcessingApplication.java
#SpringBootApplication
public class AnimalProcessingApplication {
public static void main(String[] args) {
SpringApplication.run(AnimalProcessingApplication.class, args);
run();
}
public static void run() {
ProcessAnimal processAnimal = new ProcessAnimal();
processAnimal.processAnimals();
}
}
AnimalProcessingApplication class should be one level above all other classes.
Also you are using new for creation of object instead of using Dependency Injection (autowiring).
Replace below -
ProcessAnimal processAnimal = new ProcessAnimal();
with
#Autowired
ProcessAnimal processAnimal;
Also make sure that ProcessAnimal is a bean and Animal is injected in this class using autowiring.
Animal Processing Application.java must be on root folder of all classes.
Then all components in child folders are recognized automatically.
Update:
Create a config class with #Bean method to create an instance with a Dog. Also then you can get rid of the #Component annotation of the class.
The problem here is the constructor String name which cannot be injected.
Update 2:
Don't create the instances by yourself. Let spring container create them. Remove the run method.
Following are to be done to make this program work.
1.ProcessAnimal should be made a component . Annotating the class with #Component will mark the class to be autodetected during component scan.
#Component
public class ProcessAnimal {
#Autowired
public Animal animal;
public void processAnimals() {
animal.setName("Fido");
}
}
Obtain the ProcessAnimal class from the application context. The spring will prepare the ProcessAnimal bean with all its dependencies set.
You may do this in multiple ways and following is one of those
#Component
public class CheckRedRunner implements ApplicationRunner {
#Autowired
ProcessAnimal process;
#Override
public void run(ApplicationArguments args) throws Exception {
process.processAnimals();
}
}
A bean implementing ApplicationRunner will be run when the application starts.
or else
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(AnimalProcessingApplication.class, args);
ProcessAnimal process = ctx.getBean(ProcessAnimal.class);
process.processAnimals();
}
Couple of observations
the package names by convention uses lower case letters
example : com.example.process.entity
Please go through the official documentation to learn the expected way of writing Spring boot application.

Autowire a bean in a Main program

I need to autowire a bean in a standalone main program as i need to set Up some data . Main program has a dependency on "MyDependencyClass" to set up some services.
I am unclear as to how to get the ApplicationContext as the "MyDependencyClass" is not declared in any spring xml,nor the class is annotated. Please help.
My main program :
public class Main {
#Autowired
private MyDependencyClass myDepClass
public static void main(String[] args) {
Main main1 = new Main();
main1.callDep();
}
private void callDep(){
myDepClass.setUp();
}
}
MyDependencyClass:
public class MyDependencyClass {
public void setUp() {
Sysout("Setting up");
}
}
IF you don't define beans in .xml you need to use #Component or #Repository annotation based on your class type. annotations

Create instance of call with autowire

I have to create a instance of a class, that have autowired elements, for test.
public class MyClass extends SomeOtherClass {
#Autowired
public MyClass(OtherClass1 one, OtherClass2 two){
super(one, two)
}
}
How can i in code create instance of this class, with the arguments wired in though spring?
Your test can be made Spring-aware if you use the SpringJUnit4ClassRunner to read in your Spring Context to be used in the test. For instance:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"the-config.xml"})
public final class MyClassTests {
#Autowired
private MyClass testee;
#Test
public void testSomething() {
assertThat(testee).doesSomethingExpected();
}
}
Note that you should reuse as much of your production config as possible and not create a parallel Spring Context config that mirrors it.
Instead of passing the other elements in as constructor arguments, you Autowire them as properties. Spring will then inject the objects.
public class MyClass extends SomeOtherClass {
#Autowired
private OtherClass1 one;
#Autowired
private OtherClass2 two
public MyClass(){
super(one, two)
}
}
Edit: Based on http://www.mkyong.com/spring/spring-auto-wiring-beans-with-autowired-annotation/, adding #Autowired to the constructor is also valid.
If you want to Autowire MyClass, you must annotate it with #Component or a similar annotation such as #Service.
#Component
public class MyClass extends SomeOtherClass
Then, you can use it in other classes
public class ClassThatUsesMyClass {
#Autowire
private MyClass myClass;
}

spring annotation NullPointerException

#Component
public class AnnotationTest extends TestCase{
ServiceTest serviceTest;
#Autowired(required=false)
public void setServiceTest(ServiceTest serviceTest) {
this.serviceTest = serviceTest;
}
public void testAnnotation () {
new ClassPathXmlApplicationContext(new String[]{"/com/test/spring/ioc/beans.xml"});
serviceTest.annotationTest("testName", "testPassword");
}
error:
Exception in thread "main" java.lang.NullPointerException
at com.test.spring.ioc.AnnotationTest.invokeIoC(AnnotationTest.java:16)
at com.test.spring.ioc.AnnotationTest.main(AnnotationTest.java:13)
service class:
#Service
public class ServiceTestImpl implements ServiceTest{
#Autowired
AnnotationDAO annotationDAO;
public List<String> annotationTest(String name, String pssword) {
return annotationDAO.annotationTest(name, pssword);
}
}
DAO class:
#Repository("AnnotationDAO")
public class AnnotationDAOImpl implements AnnotationDAO{
public List<String> annotationTest(String name, String pssword) {
List<String> list = new ArrayList<String>();
list.add("Test 1");
list.add("Test 2");
return list;
}
}
beans.xml:
<bean id="service" class="com.test.spring.ioc.service.ServiceTestImpl"/>
<context:annotation-config />
<context:component-scan base-package="com.test.spring" />
how can I solve this?
EDIT:
it was giving warning msg:
WARNING: Autowired annotation is not supported on static methods: public static void
com.test.spring.ioc.AnnotationTest.setServiceTest(com.test.spring.ioc.service.ServiceTest)
i moved to junit test instead of java main method as shown above by adding #Component( i am not sure this is required).
Now i am getting new error as:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name
'annotationTest': Injection of autowired dependencies failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Could not autowire field:
com.test.spring.ioc.service.ServiceTest com.test.spring.ioc.AnnotationTest.serviceTest;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No
unique bean of type [com.test.spring.ioc.service.ServiceTest] is defined: expected single
matching bean but found 2: [service, serviceTestImpl] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProce ssPropertyValues(AutowiredAnnotationBeanPostProcessor.java:287)
The problem is, you are defining the same bean twice:
Once explicitly:
<bean id="service" class="com.test.spring.ioc.service.ServiceTestImpl"/>
And once through Component Scanning:
<context:component-scan base-package="com.test.spring" />
Get rid of one of them and it will work.
BTW: you don't need to instantiate the container yourself when testing, just use the Spring TestContext Framework:
#RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from "/applicationContext.xml"
// and "/applicationContext-test.xml"
// in the root of the classpath
#ContextConfiguration({"/applicationContext.xml",
"/applicationContext-test.xml"})
public class MyTest {
// class body...
}
And of course, with JUnit 4.x you should no longer extend from TestCase, but use annotated methods instead:
#Test
public void testAnnotation () {
serviceTest.annotationTest("testName", "testPassword");
}
The AnnotationTest class is not instantiated by spring, so Spring never has a chance to inject the serviceTest dependency:
You can either explicitly get you bean:
public static void main(String[] args) {
ApplicationContext ctx =
new ClassPathXmlApplicationContext(
new String[]{"/com/test/spring/ioc/beans.xml"});
serviceTest = ctx.getBean(ServiceTest.class);
invokeIoC();
}
or you could tell annotate your AnnotationTest class with #Component so that an instance will be created by the component-scan. Note, though I think that would be a bit of a hack as you'll be instantiating an AnnotationTest object and never use it, so I'd do away with the autowiring in the main and use getBean...
EDIT:
In order to do the autowiring of a static field, you'd also have to fool spring into thinking that serviceTest is not actually static (again, I don't think that's a good idea):
#Component
public class AnnotationTest {
static ServiceTest serviceTest;
...
#Autowired
public void setServiceTest(ServiceTest serviceTest) {
AnnotationTest.serviceTest = serviceTest;
}
}

Categories

Resources