Unable to call function of autowired class - java

I have the following classes :
Class 1:
package com.assets;
#Component
#Scope("request)
public class AssetDetailsImpl implements AssetApi
{
public void function1(){
....
}
public void function2(){
AssetUtil.test1();
}
}
Class 2:
package com.assets;
#Component
public class AssetUtil
{
#Autowired
AssetDetailsImpl impl;
//some functions
public static void test1{
impl.function1();// NPE I am getting
}
Here my auto wiring not working, its coming null. Both the classes are in the same package. Is it because of the request scope which is there in AssetDetailsImpl? I even tried with #Inject that also was not working. Can anyone please help me to resolve this? Thanks in advance!
I have tried removing the scope, but then also the same problem.
I have also tried:
AssetUtil(AssetDetailsImpl impl) {
this.impl = impl;
}
But I am not sure how to deal with the static thing then also how to invoke this constructor?

The method test1 is static.
But Spring doesn't work with static members because it creates instances of the beans.
Remove static:
public void test1{
impl.function1();
}
And now you have to make sure that the client of this method is also using autowiring to get an instance of AssetUtil

It looks to me like the issue is that the AssetDetailsImpl Component is Request-scoped, which means it comes and goes with each HTTP request, while the AssetUtil Component which is trying to use it is default-scoped, which is Application/singleton scope.
Personally, I try to use singletons as much as possible. I wouldn't use request scope for the first Component.

Related

Aspect method of a parent class of a RestController does not trigger advice logic

I have some construct I'd really love to use an aspect on. I want to let my RestController inherit from a class which yields special logging methods which
log to the standard logback output
fires a http request to a service which does stuff with the log
message as well (done by the aspect)
I created an annotation with which I mark the method I want to aspect so the pointcut cant filter it. Special case is that this method is declared within the parent class of the RestController.
The aspect is not running even tho IntelliJ is marking the method as being used by the aspect, which tells me the pointcut has to be working?
Please see my code and check what I've might missed out to get it to work.
ApplicationClass
#SpringBootApplication
#ComponentScan("com.xetra.experimental")
#EnableAspectJAutoProxy(proxyTargetClass = true)
public class AopTryoutApplication {
public static void main(String[] args) {
SpringApplication.run(AopTryoutApplication.class, args);
}
}
RestController
#RestController
public class Endpoint extends SimpleLogger {
#GetMapping("/endpoint")
public void doStuff(){
log("foo");
}
}
Parent class for RestController
public class SimpleLogger implements EndpointLogger{
#AspectAnnotation
public void log(String msg) {
System.out.println(msg);
}
}
Interface for parent class (heard that aspected methods need interfaces)
public interface EndpointLogger {
void log(String msg);
}
Annotation my aspect should pointcut to
#Inherited
public #interface AspectAnnotation {
}
Spring AOP aspect
#Component
#Aspect
public class TestAspect {
#Pointcut("#annotation(com.xetra.experimental.aoptryout.AspectAnnotation)")
public void methods() {
}
#Before("methods()")
public void beforeMethodExecution(JoinPoint jp) {
System.out.println("Aspect ran!!!!");
}
}
Due to the proxy-based nature of Spring’s AOP framework, calls within the target object are by definition not intercepted.
You can find more here.
The call to log method is not intercepted since it's made from the doStuff method belonging to the same target object.
Now, any call to log method will be intercepted as long it's made externally from another object (not the same target object).
Questions
So if I use SimpleLogger as a component and not a parent class within the Endpoint it will work aye?
Yes, you are right!
Is there any way to get this to work anyway? Like using AspectJ and not Spring AOP?
You can use AspectJ's source weaving to make it work. Here, is a working example.

How to use #Before/#BeforeClass with #Autowired field

I have a test case which has an #Autowired field. I would like to have one method for setting up the test case, as it has many #Test-annotated methods that will rely on the same generated data, (for which I need the autowired class).
What's a good way to achieve this?
If I have the #BeforeClass, then I need to make the method static, which breaks the autowiring.
1st solution
Use TestNG instead.
#Before* annotations behave this way in TestNG.
No method annotated with #Before* has to be static.
#org.testng.annotations.BeforeClass
public void setUpOnce() {
//I'm not static!
}
2nd solution
And if you don't want to do that, you can use an execution listener from Spring (AbstractTestExecutionListener).
You will have to annotate your test class like this:
#TestExecutionListeners({CustomTestExecutionListener.class})
public class Test {
//Some methods with #Test annotation.
}
And then implement CustomTestExecutionListener with this method:
public void beforeTestClass(TestContext testContext) throws Exception {
//Your before goes here.
}
Self-contained in one file that would look like:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"commonContext.xml" })
#TestExecutionListeners({SimpleTest.class})
public class SimpleTest extends AbstractTestExecutionListener {
#Override
public void beforeTestClass(TestContext testContext) {
System.out.println("In beforeTestClass.");
}
#Test
public void test() {
System.out.println("In test.");
}
}
I came up with the solution of creating a separate initialization method (not setUp) annotated with #PostConstruct. This is not really an elegant solution, but it makes sure that the autowired/injected fields are properly initialized by Spring before using them, (which was the initial problem with the statically #BeforeClass annotated method).

Do Spring beans that depend on other beans get singleton versions of those beans by default?

I am new to using the Spring-Framework, and I am actually using the spring-boot library. I have the following question:
I understand that beans registered in the #Configuration class with #Bean are singleton by default, however I am finding that beans that rely on other beans are getting their own instances of those beans, not the singleton instance I would like them to have.
For example:
#Bean
public static void myFirstService() {
return new MyFirstService(foo(), bar());
}
#Bean
public static void mySecondService() {
return new MySecondService(foo(), bar());
}
#Bean
public static void foo() {
return new Foo();
}
#Bean
public static void bar() {
return new Bar();
}
I would like the instances of MyFirstService and MySecondService to have the same instances of foo and bar. That is what should be happening by default, right? Or am I misunderstanding something completely with how beans are handled?
I have played around with the #Scope annotation (to no avail), but it is my understanding I shouldn't have to.
Thanks in advance for any input! :)
No sooner had I posted this, I realised the problem... (always the way...)
I figured out the answer. Just in case anyone else made the same mistake. My IDE corrected the methods to be "static", which of course they should not be.
I have changed these methods to instance methods, and everything worked as expected.
You should have used #Autowired here as follows:
#Autowired
private MyFirstService myFirstService;
#Autowired
private MySecondService mySecondService;
And in java class code for MyFirstService and MySecondService, auto wire the foo and bar also.

How can I inform my SpringBoot-Application of a class copy?

I've got a problem with #Autowiring being null. I am looking for advice how to model it the spring-boot-way.
My Soap-Services get really big using lots of Repository classes. This gives me a large list of #Autowired already. Now when I want to call a helper-class like HeaderValidator.class I can't instantiate and call it like a POJO. This because everything annotated #Autowiring in my HeaderValidator is null. I can make it work when I add #Autowired at line (1) and remove the content of (2) in SoapServiceImpl.
But this will end in a huge list of #Autowired annotated fields and this looks ugly. I want to prevent this even it works for now.
This Article mentions the #Configurable with AspectJ. But the Article is from 2013 and Spring-Boot has developed since. I tried the #Configurable solution but it didn't work in my case.
How can I inform my SpringBoot-Application of a class copy? Is the #Configurable-way still the only one? Or did I simply model the application wrong?
Application.class:
#SpringBootApplication
public class Application {
private static ApplicationContext ctx;
public static void main(String... args) {
ctx = SpringApplication.run(Application.class, args);
publishSoapServices();
}
SoapService.class (gets published when calling publishSoapServices() in Application.class):
public class SoapServiceImpl implements SoapService {
#Autowired
ProjectRepository projectRepo;
(1) "#Autowired"
HeaderValidator headerValidator;
#Override
public EventReport send(#WebParam(name = "header") HeaderType headerType,
#WebParam(name = "content") ContentType contentType) {
return storeServiceData(headerType, messageType);
}
private EventReport storeServiceData(HeaderType headerType, ContentType contentType) {
projectRepo.save(contentType);
(2) "HeaderValidator headerValidator= new HeaderValidator()"
return headerValidator.validate(headerType);
}
My problem class:
#Service
public class HeaderValidator {
#Autowired
ValidFieldsRepository validFieldsRepo; //<-- always null!
I managed to solve my problem. It was simply due to bad design. I went trough the application and configured #Configurableit correctly. Now it works all fine. Thanks to M.Deinum!

Can I use injected beans as arguments for another class' method?

I am working on a hibernate project and I'm moving some logic from a BLL class to a DTO, and I was wondering if it's possible to inject objects into a DTO? The code from the BLL class relied on a lot of imported beans, but when I tried importing them into my DTO object my applicationContext would mess up.
FlightHelper class:
public class FlightHelper {
#Inject
private InjectedClass injectedClass;
public void testMethod(Flight flight) {
...code here
flight.getPrice(injectedClass);
}
}
Flight class:
public class Flight {
public void getPrice(InjectedClass injectedClass) {
...code here
}
}
Yes, you can.
However, the design is not very nice because you have a very strong interaction between Flight and FlightHelper classes.
yes you can, but you might want to instead inject them in the other class aswell.

Categories

Resources