google guice #Inject giving null while doing DI #Autowired in spring - spring

I am working in the spring framework and microservice arch. I have one class like MainClass.java in that I am injecting LibraryClass.java using #AutoWired. LibraryClass.java class is present inside data-lib.jar
import org.springframework.beans.factory.annotation.Autowired;
import com.data.LibraryClass;
public class MainClass {
#Autowired
LibraryClass libraryClass;
String value = libraryClass.getData();
}
Inside data-lib.jar dependency jar LibraryClass.java file look like this and I am injecting OtherLibraryClass.java using google guice DI #Inject. OtherLibraryClass.java class also present inside data-lib.jar
package com.data;
import com.google.inject.Inject;
public class LibraryClass {
#Inject
OtherLibraryClass otherLibraryClass;
public String getData() {
return otherLibraryClass.getValue(); // throwing null pointer exception
}
}
While calling getData() method from MainClass.java it is throwing null pointer exception. it is looking like OtherLibraryClass.java instance is not automatically created by Guice. If it is created by Guice then automatically Inject all dependency.
I don't want to change anything inside data-lib.jar.I can change in MainClass.java so that problem will resolve. Is there any way to work properly without any exception.
Note : data-lib.jar was build in play framework. that's why I don't want to change inside the dependency jar. If we call getData() method from other play framework serv it is working fine. Only while calling from spring frameworks serv I am facing this prob
Thanks in Advance

Related

Spring Boot 2.5 and Spring Data: #NoRepositoryBean unexpected behaviour in multi-module project

I'm facing the following issue in a legacy code that I can't change. I have a multi module project which defines in the commons module a Spring Data interface as below:
package commons;
...
#NoRepositoryBean
public interface MyCustomRepository<P, I extends Number> extends JpaRepository<MyEntity, Integer>
{
MyEntity getOneAndCheck();
}
In another module I extend this interface as follows:
package data;
...
#Repository
public interface MyRepository extends MyCustomRepository<MyEntity, Integer>
{
...
}
So, the idea is that I don't want that Spring Data generates any implementation for the MyEntity getOneAndCheck() method 'cause it is implemented like this:
package data;
...
public class MyCustomRepositoryImpl implements MyCustomRepository
{
...
#Override
public MyEntity getOneAndCheck()
{
...
}
...
}
However, when I'm starting the application, I get the following exception:
...
Caused by: java.lang.IllegalArgumentException: Failed to create query for method public abstract MyEntity commons.MyCustomRepository.getOneAndCheck()! No property getOne found for type MyEntity!
...
So what it seems to happen is that Spring Data tries to generate a Query for the MyEntity getOneAndCheck() method, despite the #NoRepositoryBean annotation. This works as expected in the application I'm gonna migrate from Spring 3 with Spring Data to Spring Boot 2.5.
Not sure if the described behavior has anything to do with the fact that there are multiple Maven modules and that the repositories, the entities and the DTOs are in different modules. Not sure neither if there should be any difference between the way it runs currently with Spring and the one with Spring Boot. But the result is that all of the dozens of repositories in this legacy application are failing with the mentioned exception.
It might be important to mention that the main class needs to use annotations in order to tune the scanning:
#SpringBootApplication(scanBasePackages = "...")
#EnableJpaRepositories(basePackages={"...", "..."})
#EntityScan(basePackages= {"...", "..."})
public class MyApp
{
public static void main(String[] args)
{
SpringApplication.run(MyApp.class, args);
}
}
Not sure whether these annotations are supposed to change anything from the point of view of #NoRepositoryBean but the issue appeared as soon as I added this Spring Boot main class. It worked okay previously without Spring Boot.
Any suggestion please ?
Many thanks in advance.
Kind regards,
Seymour
There are two things that play together:
Spring Data's default custom implementation
Repository fragments
None of these apply because:
The default custom implementation follows the name of the actual repository. In your case, the implementation is named MyCustomRepositoryImpl whereas the repository name is MyRepository. Renaming the implementation to MyRepositoryImpl would address the issue
Since Spring Data 2.0, the repository detection considers interfaces defined at the repository level as fragment candidates where each interface can contribute a fragment implementation. While the implementation name follows the fragment interface name (MyCustomRepository -> MyCustomRepositoryImpl), only interfaces without #NoRepositoryBean are considered.
You have three options:
extracting your custom method into its own fragment interface and providing an implementation class that follows the fragment name:
interface MyCustomFragement {
MyEntity getOneAndCheck();
}
class MyCustomFragementImpl implements MyCustomFragement {
public MyEntity getOneAndCheck() {…}
}
public interface MyRepository extends MyCustomRepository<MyEntity, Integer>, MyCustomFragment {…}
Set the repositoryBaseClass via #EnableJpaRepositories(repositoryBaseClass = …) to a class that implements the custom method.
If you cannot change the existing code, you could implement a BeanPostProcessor to inspect and update the bean definition for the JpaRepositoryFactoryBean by updating repositoryFragments and adding the implementation yourself. This path is rather complex and requires the use of reflection since bean factory internals aren't exposed.

How to use #Autowired annotation two or more different Component class for same service?

For example, have a class like as follows.
First XService service in class A is not null but second XService service in AmountValidator is null.I get NullPointerException I try to create bean new it works and then I get same exception when call AmountValidateService outsideRestService in XService.
How can I use XService everywhere that I use #Autowired annotation.
My main class:
#Service
class A extends AbstractA implements IA {
#Autowired
XService service; //first autowired definition. code go to check() method. service not null now.
public doSometing(){
validator.check();
service.methodA();
super.AbstractMethod();
}
}
Validator class used in class A :
class Validator<T> implements IValidator<T> {
public void check(){
rule.check(); // rule have a implements IValidator eg: amountValidator, dateValidator class
}
}
AmountValidator added to rule in class Validator.
#Component
class AmountValidator implements IValidator<T>{
#Autowired
XService service; // code comes here service is null. same service class mentioned above class A.
#Override
public void check(){
service.validateAmount(); // nullPointerException.
}
}
My main Service
#Component
class XService {
#Autowired
AmountValidateService outsideRestService;
public validateAmount(){
outsideRestService.validate(); // nullPointer when create XService with the `New` keyword
}
}
You have an error cause you are trying to create components/beans/services yourself. As i mentioned in comment when you create components yourself it - #Autowired doesn't work - thats you've got NPE
All classes annotated with #Component, #Service are considered special classes which are instantiated by Spring automatically via DI, instantiating them with new defeats the purpose of DI.
These special classes are named Spring Beans.
Every time the application starts, the framework instances all Spring Beans, and all #Autowired fields are injected by Spring automatically. But the Spring Beans must be defined somewhere in the class path. Else you will receive a NoSuchBeanDefinitionException
As an attempt to answer the question, since I don't have a stack trace nor all the Spring Bean definitions:
When you instantiate XService using new XService() your new instance will not actually initialize the field AmountValidateService outsideRestService, effectively leaving it as null.
You may set the field yourself but as I mentioned earlier, it defeats the purpose of DI
Your question is not complex, it is incomplete.

Spring Boot Dependency with Spring 3

I have a Spring 3 dependent project which I am using in my latest spring boot project
I am facing issues with auto wiring
my spring 3 project has a Gateway Interface (IAccountGateway)
I am facing an issue like
Description:<br>
<br>Field iAccountGateway in
com.rvi.service.common.impl.RegistrationService required a bean of type
'com.rvi.jms.gateway.IAccountGateway' that could not be found. <br><br>Action:<br>
Consider defining a bean of type 'com.rvi.jms.gateway.IAccountGateway'
in your configuration.
when I put debug in my spring project I got log something like below
Registered injected element on class <br><br>
[com.rvi.service.common.impl.RegistrationService]:
AutowiredFieldElement for private com.rvi.jms.gateway.IAccountGateway
com.rvi.service.common.impl.RegistrationService.iAccountGateway
Well, if IAccountGateway is an interface, then, you need to implement it and define as a Spring Bean with #Component annotation (there are also other annotations that have similar effect).
IAccountGateway.java
public interface IAccountGateway {
// ..
}
AccountGatewayImpl.java (the IAccountGateway implementation)
import org.springframework.stereotype.Component;
#Component
public class AccountGatewayImpl implements IAccountGateway {
// ..
}
Autowiring the field:
import org.springframework.beans.factory.annotation.Autowired;
public class Clazz {
#Autowired
IAccountGateway iAccountGateway;
// ..
}
See Spring Boot Reference on Spring Beans and Dependency Injection

Using Spring boot, I am unable to refer a class present in another jar

I am trying to build a spring boot web application. I want to refer a class from another jar. The class name is SalaryHandler.
I have done the following configuration in the class having
#SpringBootApplication annotation:
#Bean
public SalaryHandler iSalary() {
return new SalaryHandler();
}
In the class, where it is required, I have used autowiring annotation like this:
package hello;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import com.salary.SalaryHandler;
//#Service - not working
//#Component - not working
public class SalaryDelegatorImpl implements SalaryDelegator {
#Autowired
private SalaryHandler iSalary;
#Override
public void show() {
iSalary.testSalary();
}
}
The code is compiling fine, but when this iSalary object is used to call its method, nullpointer exception is thrown.
Just to note that SalaryHandler is present inside another jar and is not using any spring annotation, its code is as below:
package com.salary;
public class SalaryHandler implements ISalary {
public void testSalary() {
System.out.println("Salary test successful...");
}
}
you need to attempt Autowire with #Component. In order to get this to work, you'll have to annotate a method in your #Configuration class. Something like this should allow you to autowire the class:
#Configuration
#ComponentScan("com.package.where.my.class.is")
public class ConfigClass{
#Bean
public JPADataService jpaDataService(){
return new JPADataService();
}
}
I am able to fix this. The problem was somewhere inside code, I was calling SalaryDelegatorImpl using new operator(from inside a factory class), so that was not being managed by Spring. As a result, the #Autowired on SalaryHandler, was not working.
I changed my factory to be spring managed, and then it worked fine.
Thanks everyone for the support.

Spring dynamic autowire services

I've started to build some kind of a CMS and I'm stuck over one idea.
The description is:
I have standard MVC Controller (Home) in which I'm downoading modules settings which will be set in this Controller.
The response is, that I have to implement module with name "HPModule".
So I'm trying to load this module by Class.forName("com.app.something.HPModule"); and then call method init();
My HPModule is:
public class HPModule
{
#Resource(name = "hpModuleService")
private HPModuleService hpModuleService;
public String init()
{
SomeObject someObject = hpModuleService.getArticle();
}
}
And I found that when I'm trying to do SomeObject someObject = hpModuleService.getArticle(); Spring is blind for #Resource when I'm calling class by Class.forName.
How to solve this issue?
The HPModule has to be a Spring Bean retrieved by means of DI or directly from Spring BeanFactory. You cannot expect Spring to autowire a class that is not instantiated by Spring, unless You use #Configurable and AspectJ to weave the class.
If HPModule already is a Spring Bean, than just #Autowire or #Inject it directly into the MVC controller that needs it.
If You don't know in compile time what modules You'll need, than inject ListableBeanFactory and use BeanFactoryUtils to get the modules You need in runtime by type or by name.

Resources