I'm receiving a null pointer exception when operating on my service because my service is not being Autowired into the class. I've implemented this class's repository and service exactly the same as others in this application and I haven't had this problem before. The class does in fact warn about issues with the Autowire but I'm not sure how to fix them:
Autowired members must be defined in valid spring bean
Again, this is set up the same as other classes and I do not have this issue. Within the service class, it complains that the repository cannot be autowired into the constructor because there are multiple beans of the same type. My other service class shows this warning as well but does not have problems being Autowired into classes and operated upon. Definitions below, please ask for any other context that would be helpful.
//TransactionCategoryRepository.java
#Repository("transactionCategoryRepository")
public interface TransactionCategoryRepository extends
CrudRepository<TransactionCategory, Integer> {
}
--
//TransactionCategoryService.java
#Service("transactionCategoryService")
public class TransactionCategoryService {
private TransactionCategoryRepository transactionCategoryRepository;
#Autowired
public TransactionCategoryService(TransactionCategoryRepository repository) {
this.transactionCategoryRepository = repository;
}
public void saveTransactionCategory(TransactionCategory transactionCategory) {
transactionCategoryRepository.save(transactionCategory);
}
}
--
//Utilities.java
public class PlaidUtilities {
private Logger logger =
LoggerFactory.getLogger(PlaidUtilities.class.getSimpleName());
private PlaidClient mPlaidClient;
#Autowired
TransactionCategoryService mTransactionCategoryService;
...
The multiple bean warning is thrown on respository in TransactionCategoryService.java and the Autowired definition warning is thrown in Utilities.java. The breaking null pointer exception error occurs later in Utilities.java when operating on mTransactionCategoryService.
Unless you need them, take the names out of the #Service and #Repository annotations. I've found it just makes things awkward.
The other thing that might be wrong is that you're not scanning those packages. You can change that in your main class by altering the boot application attribute to #SpringBootApplication(scanBasePackages={"your.package.here"})
Have a look here at this question where they detail it
Related
In my spring boot application I have multiple #Service implementations of an interface. Which of these implementations is used at runtime for any given request is configured in a databse.
Something like this:
Value
Service Bean
Hello
ServiceA
World
ServiceB
Foo
ServiceA
Bar
ServiceC
The correct bean is then retrieved using the application context and the defined Service Bean Name from the database. However it could be possible that a Service Bean is mentioned in the database that does not exist in the application context. I'd rather detect this during startup than at runtime.
This question basically boils down to how you add your own validation to the spring boot startup process or what's the best practice? I tried throwing an Exception when creating the bean, that deals with the mapping of values to Service Beans, and handling it with my own FailureAnalyzer. But the FailureAnalyzer never gets called because due to the missing bean an UnsatisfiedDependencyException is also thrown and causes the application to stop.
I found a solution that I'm happy with.
I did not register my FailureAnalyzer in my resource folder in the META-INF/spring.factories file.
As described in the question throwing my Exception during bean creation caused an UnsatisfiedDependencyException. So instead I used an ApplicationListener and perform my check, when the application is ready but has not yet started.
#Component
public class ApplicationReadyListener implements ApplicationListener<ApplicationReadyEvent> {
#Override
public void onApplicationEvent(ApplicationReadyEvent event) {
if(!checkConsistency())
throw new MyRuntimeException();
}
}
Now my FailureAnalyzer gets called and handles MyRuntimeException and stops the application with a proper message.
#Component
public class MyRuntimeExceptionFailureAnalyzer extends AbstractFailureAnalyzer<MyRuntimeException> {
#Override
protected FailureAnalysis analyze(Throwable rootFailure, MyRuntimeException cause) {
return new FailureAnalysis(buildErrorMessage(cause), buildActionMessage(cause), cause);
}
}
Edit Fixed by changing package.
I have this configuration file for spring framework
#Configuration
public class AppConfig {
#Bean(initMethod = "populateCache")
public AccountRepository accountRepository(){
return new JdbcAccountRepository();
}
}
JdbcAccountRepository looks like this.
#Repository
public class JdbcAccountRepository implements AccountRepository {
#Override
public Account findByAccountId(long
return new SavingAccount();
}
public void populateCache() {
System.out.println("Populating Cache");
}
public void clearCache(){
System.out.println("Clearing Cache");
}
}
I'm new to spring framework and trying to use initMethod or destroyMethod. Both of these method are showing following errors.
Caused by: org.springframework.beans.factory.support.BeanDefinitionValidationException: Could not find an init method named 'populateCache' on bean with name 'accountRepository'
Here is my main method.
public class BeanLifeCycleDemo {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = new
AnnotationConfigApplicationContext(AppConfig.class);
AccountRepository bean = applicationContext.getBean(AccountRepository.class);
applicationContext.close();
}
}
Edit
I was practicing from a book and had created many packages for different chapters. Error was it was importing different JdbcAccountRepository from different package that did not have that method. I fixed it and it works now. I got hinted at this from answers.
Like you said, if you are mixing configurations types, it can be confusing. Besides, even if you created a Bean of type AccountRepository, because Spring does a lot of things at runtime, it can call your initMethod, even if the compiler couldn't.
So yes, if you have many beans with the same type, Spring can be confused an know which one to call, hence your exception.
Oh and by the way, having a Configuration creating the accountRepoisitory Bean, you can remove the #Repository from your JdbcAccountRepository... It is either #Configuration + #Bean or #Component/Repository/Service + #ComponentScan.
TL;DR
Here is more information and how Spring creates your bean : What object are injected by Spring ?
#Bean(initMethod = "populateCache")
public AccountRepository accountRepository(){
return new JdbcAccountRepository();
}
With this code, Spring will :
Detect that you want to add a Bean in the application Context
The bean information are retrieved from the method signature. In your case, it will create a bean of type AccountRepository named accountRepository... That's all Spring knows, it won't look inside your method body.
Once Spring is done analysing your classpath, or scanning the bean definitions, it will start instanciating your object.
It will therefor creates your bean accountRepository of type AccountRepository.
But Spring is "clever" and nice with us. Even if you couldn't write this code without your compiler yelling at you, Spring can still call your method.
To make sure, try writing this code :
AccountRepository accountRepository = new JdbcAccountRepository();
accountRepository.populateCache(); // Compiler error => the method is not found.
But it works for Spring... Magic.
My recommandation, but you might thinking the same now: If you have classes across many packages to answer different business case, then rely on #Configuration classes. #ComponentScan is great to kickstart your development, but reach its limit when your application grows...
You mix two different ways of spring bean declaration:
Using #Configuration classes. Spring finds all beans annotated with #Configuration and uses them as a reference to what beans should be created.
So if you follow this path of configuration - don't use #Repository on beans. Spring will detect it anyway
Using #Repository - other way around - you don't need to use #Configuration in this case. If you decide to use #Repository put #PostConstruct annotation on the method and spring will call it, in this case remove #Configuration altogether (or at least remove #Bean method that creates JdbcAccountRepository)
Annotate populateCache method with #PostConstruct and remove initMethod from #Bean. It will work.
Can i make my repository be accessed in a class who isn't a RestController or something like that ?
I have an WatchService who listen a folder, to reads the files and after persist to a database. My watchservice works just like reading files, but I want persist using my JPARepository to persists, can i do that?
Springboot Application v2.1.6.RELEASE
#Repository
public interface MyRepository extends JpaRepository<MyClass, Long> { }
public class MyWatchService implements Runnable{
#Autowired
private MyRepository myRepository;
// SOME CODES COMES HERE
#Override
public void run() {
// SOME CODES COMES HERE
myRepository.save(MyClass); // In this point give a nullPointerException
}
}
I get that Exception:
java.lang.NullPointerException
at com.WatchService.run(WatchService.java:515)
at java.base/java.lang.Thread.run(Thread.java:835)
You get the NullPointerException because the dependency did not get injected. You used the annotation correctly, but the dependencies do not get injected, by some magic.
In order for this to work (i.e. for the beans to get injected), you need to let the DI- or IoC Container instantiate the bean for your (in JEE this would be CDI, in Spring it is the Spring IoC Container). This can be done by injection (d'uh! Injection-inception) or programmatically.
A Spring-centric solution is explored in this question.
I got a project with tons of services and repositories. Currently each repository is autowired to a service using annotations.
#Service
public class Service1 {
#Autowired
private Repository1 repository1;
#Autowired
private Repository2 repository2;
...100+ more
}
All of these repository are under the same package. Is it possible to skip declaration for each repository?
A simple solution I found would be to implement an interface like this:
#Autowired
private Map<String,RepositoryInterface> repositoryInterface
public void method1(){
repositoryInterface.get("repository1").doMethod();
}
It should have been a good solution but problem is I don't have access to all the source codes. I have tons of repository classes that I am not allowed to change to add an interface class.
So is there another way to solve this? Like just scan the whole package and just use bean name to access the repositories?
Beans are retrievable from their class or their name (and both).
In your case, you could rely directly on their class to retrieve them from the context.
Inject an ApplicationContext (or constructor way) :
#Autowired
private ApplicationContext applicationContext;
And use it :
applicationContext.getBean(RepositoryOne.class).doMethod1();
Ideally it should be extracted into a method :
public <T> T getRepository(Class<T> clazz){
return applicationContext.getBean(clazz);
}
to be used more simply :
getRepository(RepositoryOne.class).doMethod(1);
But I would warn about needing so many field dependencies in a class.
This makes it very hard to maintain/to test and also very error prone to use.
The best thing to do is rethink your design to avoid such complex/bloat class.
Besides using structure like private Map<String,RepositoryInterface> repositoryInterface or ApplicationContext will make you lose the benefit from dependency checks performed by the Spring container at startup that prevents NullPointerException and errors related to inconsistency (dependency missing) during the application working.
in my service layer
public class MyServiceLayerImpl{
public void method1(){
MyServicelayer.method(); //is this correct?
}
public void method2(){
}
#Autowired
MyServiceInterface MyServiceLayer;
}
if i have method inside service layer that need to call another service inside service layer. i cannot use this._method ,because, i'm using AOP for caching. In order for the caching to work, i have to use #Autowired to get the service. Therefore, is the above style ok?
i get below error
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.company.iss.services.MyServiceLayerImpl#85aedd': Autowiring of fields failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.company.iss.services.MyServicelayer com.company.iss.services.MyServiceLayerImpl.MyServiceLayer; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [com.company.iss.services.MyServiceLayer] is defined: Unsatisfied dependency of type [interface com.company.iss.services.MyServiceLayer]: expected at least 1 matching bean
It's hard to tell from the weird formatting and naming, but if you want to call one service from another:
public interface MasterService {
void someMethod();
}
public class MasterServiceImpl implements MasterService {
private OtherService otherService;
public void someMethod() {
this.otherService.someCallOnOtherService();
}
#Autowired
public void setOtherService(OtherService otherService) {
this.otherService = otherService;
}
}
Now, you must have configured both MasterServiceImpl and whatever implements OtherService. There are many ways to do this, the most popular being explicitly in your XML configuration with annotation-based configured a close second.
Also note that AOP tends to be very flaky if you aren't using interfaces. In your code, your Impl doesn't actually implement anything. I would recommend against that.
Apart from having an uppercase variable and no colon - it's fine.
You would, of course, need to define your class as a bean. Either by using the #Service (or another stereotype) annotation on it, or using <bean> in applicationContext.xml (see here for the annotation-based config introduced in spring 2)
Another thing: your member variables should be lowercase, not uppercase.