NullPointerException when autowiring into non-spring managed class (POJO) - Spring Boot - java

I'm relatively new to Spring Boot and dependency injection overall, so please forgive any noob things going on here. I'm building an API and am having trouble when injecting dependencies into a POJO resource (DTO).
When I call the method in the POJO this.numComments = commentSvc.getAllForPhoto(this.getId()); I am getting a NullPointerException. However, when I do this from another spring-managed bean and pass the values into the constructor, it works fine.
After reading around, it looks like I need to do something with aspectJ and Load Time Weaving, but I'm not sure what that would look like in my code.
In essence, my approach looks something like this:
PhotoResource.java (POJO)
public class PhotoResource extends BaseRepresentable {
#Autowired
CommentService commentSvc;
private Long id;
private Integer numComments;
PhotoResource(PhotoEntity entity){
super(entity);
this.setId(entity.getId);
this.numComments = commentSvc.getAllForPhoto(this.getId());
}
}
CommentService.java
#Service
public class CommentService{
public List<CommentResource> getAllForPhoto(Long photoId) {
// code to get all comments for photo
}
}
Application.java
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}

Spring won't inject the dependency unless you ask the Spring container to manage the bean. In order for commentSvc to be injected into PhotoResource class, you need to annotate it with #Component or #Bean or #Service, e.g.:
#Component
public class PhotoResource extends BaseRepresentable {
#Autowired
CommentService commentSvc;
}
And make sure the package of this class is included into #ComponentScan packages.
Also, the following won't compile:
#Service
public class CommentService(){
You don't need paranthesis to declare a class, it should be:
#Service
public class CommentService{

Related

Dependency injection from Quarkus (java)

Colleagues, hello! Is is possible to inject beans inside of class which is created via 'new' operator?
For example:
public class TestClass implements Callback {
#Inject
TestClassRepository repository;
//just only methods...
}
And 'TestClass' is created from another class:
Flyway.configure().collbacks(new TestClass()).load();
I have an issue with this,because 'repository.anyMethods()' inside of TestClass creates 'NullPointer' exception.
'TestClassRepository' is marked with the '#ApplicationScoped' and '#Startup' annotations.
#Singleton
public class TestConfig {
#javax.enterprise.inject.Produces
public TestClass testClass() {
return new TestClass();
}
}
another class annotated with the #ApplicationsScoped or #Singleton:
#Inject
public void method(TestClass testClass) {
Flyway.configure().collbacks(testClass).load();
// your code
}
If you create an object by yourself calling a constructor (new TestClass()) then quarkus doesn't manipulate that object, and doesn't inject a repository.
No you cannot inject beans inside a class that is instanciate with the new keyword.
But you can still find a way around like so :
#Dependent
public class BeanFactory {
#Inject
TestClassRepository repository
#Produces
public TestClass createTestClass() {
return new TestClass(this.repository);
}
You can find more details here : Quarkus Contexts and dependency Injection
Also you can define multiple beans for different profiles as mentionned few lines bellow Here
This means you can create a repository for your tests and one for prod or whatever is best for your case.
Also I do not think the annotation "#Startup" would add anything to your TestClassRepository bean.

Getting null for Autowired bean created using Java config

I am creating a REST service in Spring boot. I am creating a bean in config class and trying to use in service class by auto wiring, but I am always getting null, I have tried in constructor injection as well but not working. Below is the code,
Main app
#SpringBootApplication
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
}
REST controller
#RestController
#RequestMapping("/v1")
public class RestController {
#Autowired
private Service service;
Service
#Service
public class ServiceImpl implements Service {
//This is the bean
#Autowired
private Record record;
public ServiceImpl() { //-----------------> tried injecting in constructor as well
System.out.println(record); //-------------------> null
}
Config class
#Configuration
public class AppConfig {
#Bean
public Record record() {
return new Record("test");
}
}
I noted whenever I remove the record() from config class I get below error
required a bean of type 'com.ns.service.Record' that could not be found
And after adding the method the error is not reported but null is returned, which indirectly means record() is considered as returning the required bean.
I can't find what I am doing wrong please advise.
Project folder structure
I think you're doing everything right conceptually
Spring creates an object first and only after that injects the values (technically done in bean post processors):
So try this:
#Service
public class ServiceImpl implements Service {
//This is the bean
#Autowired
private Record record;
public ServiceImpl() {
// here the record is null - not injected yet
System.out.println(record);
}
#PostConstruct
public void checkThisOut() {
// here print the record
}
You say you've tried constructor injection as well - it should work because spring has to inject something into the constructor of a bean (ServiceImpl) or fail. Please show the code snippet
One this that might be wrong in some level (although it doesn't sound like this from your description) is that you have to put all the #Configuration/#Service annotated classes in the package that is the same or underneath the package where you've created the main class annotated with #SpringBootApplication annotation. It instructs spring boot where to look for the beans.
So make sure your classes obey this rule...

Autowire a Spring bean in a Singleton class

I am trying to autowire a bean inside of a Singleton class, I know that it always a best idea to avoid manual autowiring, but this class is being used in so many places so I do not want to change the caller of this class.
Runner.java
#Component
public class RunnerClass {
#Autowired
public ConfigService configService;
}
ConfigService.java
#Service
public class ConfigService {
private ConfigServiceDAO = ConfigServiceDAO.getInstance();
}
ConfigServiceDAO.java
public class ConfigServiceDAO {
//Bean I want to autowire here....
#Autowired
ConfigServiceDAOBuilder DAOBuilder
public static ConfigServiceDAO getInstance() {
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder {
public static final ConfigServiceDAO INSTANCE = new ConfigServiceDAO();
private SingletonHolder() {}
}
}
DAOBuilder inside ConfigServiceDAO is always null, which makes sense because my understanding is when the class is instantiated manually, spring injection doesn't happen.
What could be the solution here if I want to keep ConfigServiceDAO as non spring component?
====EDIT====
I know it is possible to make ConfigServiceDAO as a spring component and autowire all dependencies.
But a lot of classes from different packages already call
ConfigServiceDAO.getInstance().someMethod()
So I guess the the right question is, what would be the best way to autowire a spring component to the class that is instantiated manually.
I don't know your use case but you cannot use #Autowired annotation outside a Spring bean.
However if you really need to access a Spring bean from a non Spring piece of code you can do it like below. However this is a very non Spring way of designing your dependencies.
import org.springframework.context.ApplicationContext;
public enum ApplicationContextHolder {
INSTANCE;
private ApplicationContext applicationContext;
public ApplicationContext getApplicationContext() {
return applicationContext;
}
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
}
Then you have a configuration class:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
#Configuration
public class SomeConfig {
#Autowired
private ApplicationContext applicationContext;
#PostConstruct
public void init() {
ApplicationContextHolder.INSTANCE.setApplicationContext(applicationContext);
}
}
Then in your DAO class you get a reference to the builder bean you are interested. Something like this:
public class ConfigServiceDAO {
public static ConfigServiceDAO getInstance() {
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder {
public static final ConfigServiceDAO INSTANCE =
ApplicationContextHolder.INSTANCE.getApplicationContext().getBean(ConfigServiceDAOBuilder.class).buildConfigServiceDAO()
private SingletonHolder() {}
}
}
Again this is a very non Spring way of doing things.
Spring processed #Autowired only in beans that it manages by itself.
So you have two choices:
Get Rid Of singleton - if you're using spring, its already a singleton in the application context. This is by far the best approach in general (assuming other parts of application that call your singleton are also spring driven). I don't think you should fear to change ConfigServiceDAO.getInstance.method() - refactoring tools in IDE will do the job.
If you can't do 1, Don't use autowired annotation in the singleton - its useless anyway, instead, when you have an application context configured (in listener that spring emits when the application started for example), get the access to the ConfigServiceDAOBuilder bean by calling appCtx.getBean(ConfigServiceDAOBuilder.class) and "inject it" manually by reflection, this is what Spring does with spring managed beans anyway:
#EventListener
public void onApplicationReadyEvent(ApplicationReadyEvent event) {
ConfigServiceDAOBuilder builder =
event.getApplicationContext().getBean(ConfigServiceDAOBuilder.class);
ConfigServiceDao dao = ConfigServiceDAO.getInstance();
dao.setDaoBuilder(builder); // or alternatively by reflection
}
As a side note, consider using method setDaoBuilder to be a package private to protect the singleton from some accidentally calling a setter
As far as I understand what you want: Create by Spring ConfigServiceDAOBuilder. After that inject it into non-managed object of class ConfigServiceDAO. You can do it after the Spring application context is instantiated. For example with CommanLineRunner:
#Component
public class CommandLineAppStartupRunner implements CommandLineRunner {
#Autowired
ConfigServiceDAOBuilder DAOBuilder
#Override
public void run(String...args) throws Exception {
ConfigServiceDAO.getInstance().init(DAOBuilder);
}
}
In ConfigServiceDAO has to be method init that helps to register all needed beans.
I'm confused after reading your comments, hence let me put in this way. What you are referring to manual autowiring is the Spring dependency injection way.
Whenever you are using any of the Spring Stereotype annotations with default scope instance is always Singleton.
Your ConfigService class has the problem.
Your are mixing up things, you should create a separate config class with #configuration and create Bean for the class ConfigServiceDAO, something like below
#Configuration
Class Config{
#Bean
public ConfigServiceDAO configServiceDAO( ){
return ConfigServiceDAO.getInstance();
}
}
then autowire the ConfigServiceDAO in the ConfigService class. With this Spring will resolve all of the dependency in correct order and DAOBuilder shouldn't be null.

#Autowire Spring Bean with Injected Constructor args?

I have a project structure similar to the one linked here: https://stackoverflow.com/a/29583882/1243462 . I have a util library containing a Service class in one JAR, meant to be consumed from another Java library/Maven project. However, my Service class itself uses Constructor Injection. So, where the original question had:
#Service
public class PermissionsService { ... }
I have
#Service
public class PermissionsService {
public PermissionsService(#Autowired PermissionsDao dao) {
//assign private dao field to autowired dao
}
}
And, like the original post, I want to create an instance of PermissionsService and inject it into my client/consumer application. I'm not sure of how to create a Configuration class.
#Configuration
public class PersistenceConfig {
public PermissionsService getPermissionsServiceBean() {
//What goes here?
}
}
For now, I have a workaround where I replaced the #Autowired PermissionsDao constructor argument with a field injection, and having a no-args constructor. This allows me to:
#Configuration
public class PersistenceConfig {
public PermissionsService getPermissionsServiceBean() {
return new PermissionsService();
}
}
But, since Field injection is discouraged, what is the right way to structure this code?
In your main module
#Configuration
#Import(PersistenceConfig.class)
public class ServiceConfig() {
}
In your utils module
#Configuration
#ComponentScan(basePackages = {"path-to-persistence-service-and-any-dependencies"})
public class PersistenceConfig {
}
The fact that you use constructor injection for PermissionsDao should not matter if you get the configuration right.

Spring Dependency injection for interfaces

Well I've been watching some tutorials about Spring dependency injection as well as MVC, but I still seem to not understand how we can instantiate classes specifically?
I mean if for instance I have a variable
#Autowired
ClassA someObject;
How can I make spring create someObject as an Instance of ClassB which would extend ClassA? like someObject = new ClassB();
I don't really understand how it works in spring, does the ContextLoaderListener do it automatically or do we have to create some kind of configuration class where we specify exactly what spring should instantiate those classes to? (In this case I haven't seen that anywhere in the tutorials) If yes, then how do we specify and how does it look like? And how do we configure it to work in web.xml, etc?
You can do it like this:
Interface:
package org.better.place
public interface SuperDuperInterface{
public void saveWorld();
}
Implementation:
package org.better.place
import org.springframework.stereotype
#Component
public class SuperDuperClass implements SuperDuperInterface{
public void saveWorld(){
System.out.println("Done");
}
}
Client:
package org.better.place
import org.springframework.beans.factory.annotation.Autowire;
public class SuperDuperService{
#Autowire
private SuperDuperInterface superDuper;
public void doIt(){
superDuper.saveWorld();
}
}
Now you have your interface defined, written an implementation and marked it as a component - docs here. Now only thing left is to tell spring where to find components so they can be used for autowiring.
<beans ...>
<context:component-scan base-package="org.better.place"/>
</beans>
You have to specify the type of the class that you want to create object of in your applicationContext.xml file or you can directly annotate that class with any of #Component , #Service or #Repository if you are using latest version of Spring. In web.xml, you have to specify path of xml files as a context-param to servlet, if you are using xml-based configuration.
Yes, you have to provide a context.xml file in which you specify the instances. Give it to the ApplicationContext and it will autowire all fields for you.
http://alvinalexander.com/blog/post/java/load-spring-application-context-file-java-swing-application
Best Practices
#RestController
#RequestMapping("/order")
public class OrderController {
private final IOrderProducer _IOrderProducer;
public OrderController(IOrderProducer iorderProducer) {
this._IOrderProducer = iorderProducer;
}
#GetMapping("/OrderService")
void get() {
_IOrderProducer.CreateOrderProducer("This is a Producer");
}
}
Interface
#Service
public interface IOrderProducer {
void CreateOrderProducer(String message);
}
Implementation
public class OrderProducer implements IOrderProducer{
private KafkaTemplate<String, String> _template;
public OrderProducer(KafkaTemplate<String, String> template) {
this._template = template;
}
public void CreateOrderProducer(String message){
this._template.send("Topic1", message);
}
}
You need to include Project Lombok dependency in spring boot
Gradle implementation 'org.projectlombok:lombok'

Categories

Resources