i create simple spring project and i need to use annotation #Autowired but when i run project, i get exception NullPointerException.
This is my classes:
Main.java
public class Main {
#Autowired
private static InjectClass injectClass;
public static void setInjectClass(InjectClass injectClass) {
Main.injectClass = injectClass;
}
public static void main(String[] args) {
injectClass.hello(); //NullPointerException
}
}
ConfigurationBean
#Configuration
public class ConfigurationBean {
#Bean
public InjectClass injectClass(){
return new InjectClass();
}
}
InjectClass
public class InjectClass {
public void hello(){
System.out.println("Autowired success!");
}
}
You need to initiate application contex before using any bean.
You can do it by writing following code in starting of your main method.
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(
ConfigurationBean.class);
Related
I have developed a basic CRUD using spring boot and it is working correctly. My main codes are the following:
Application:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Controller:
#RestController
#CrossOrigin(origins="http://localhost:4200")
#RequestMapping(value="/api")
public class Controller {
#Autowired
private PruebaService pruebaservice;
#PostMapping("save-prueba")
public ResponseEntity<?> savePrueba(#RequestBody PruebaDTO pruebaDTO) {
Prueba prueba = new Prueba(pruebaDTO.getColumna());
pruebaservice.savePrueba(prueba);
return new ResponseEntity(new Mensaje("Guardado correctamente"), HttpStatus.OK);
}
//Other methods for the CRUD
}
Service:
#Service
#Transactional
public class PruebaService {
#Autowired
private PruebaRepository pruebadao;
public Prueba savePrueba(Prueba prueba) {
if (prueba != null)
return pruebaRepository.save(prueba);
return new Prueba();
}
//Other methods for the CRUD
}
Repository:
#Repository
public interface PruebaRepository extends JpaRepository<Prueba, Integer> {
Void save(Optional<Prueba> PruebaToUpdate);
}
This CRUD is working correctly when I used it from the web application, but my problem is when I try to use the code from a main class (local).
So I have the following code that it is not working:
Main:
public static void main(String[] args) {
PruebaService pruebaService = new PruebaService();
Prueba prueba = new Prueba("prueba");
pruebaService.savePrueba(prueba);
}
This does not work because it returns a null pointer exception because pruebaRepository is not initialiced in pruebaService, so the questions are:
How is possible that the repository class is inicialited if I use a http request (by the controller class) but it is not when I use a "local" way?
How can I resolve the problem?
I want to new a project like mybatis-spring-boot-starter, I use springboot 2.3.2, but something wrong.
First of all, I define a BatisProperties.java like following:
#ConfigurationProperties(prefix = BatisProperties.MYBATIS_PREFIX)
public class BatisProperties {
public static final String MYBATIS_PREFIX = "batis";
private String MyClassName;
...
}
then, a BatisAutoConfiguration.java
#Configuration
#ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })
#EnableConfigurationProperties(BatisProperties.class)
public class BatisAutoConfiguration implements InitializingBean {
private final BatisProperties properties;
#Override
public void afterPropertiesSet() throws Exception {
checkConfigFileExists();
}
private void checkConfigFileExists() {
System.out.println(this.properties.getMyClassName());//null here
if (this.properties.isCheckConfigLocation() && //code from mybatis-spring-booot-starter
StringUtils.hasText(this.properties.getConfigLocation())) {
Resource resource = this.resourceLoader.getResource(this.properties.getConfigLocation());
Assert.state(resource.exists(),
"Cannot find config location: " + resource + " (please add config file or check your Mybatis configuration)");
}
}
And in /resource/META_INF/spring.factories
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
xxx.BatisAutoConfiguration
above are all in a starter, I compile it to a jar file and use this jar file in another project(project TWO), in project TWO, I define .properties or .yml in /resource directory, contents are:
batis.my-class-name=xxxx.xxxx
Finally, a DemoApplication.java or Test.java like following:
DemoApplication.java
#SpringBootApplication
public class DemoApplication {
#Autowired
private BatisProperties properties;
private static BatisProperties batisProperties;
#PostConstruct
public void init() {
batisProperties = properties;
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
System.out.println(batisProperties.toString());//xxxx.BatisProperties#436390f4
System.out.println(batisProperties.getMyClassName());//null
}
}
Test.java
#SpringBootTest
class Test {
#Autowired
private BatisProperties properties;
#Test
void contextLoads() {
System.out.println(properties);// some bean in Spring IOC
System.out.println(properties.getDatasourceConfigProviderClassName());// null
}
}
Above comments are the results: We can find BatisProperties Bean in Spring IOC, but all properties are null.
So anybody can help? I don't know whether it is caused by the version of SpringBoot
I would improve the BatisProperties class to be as:
#Configuration
#ConfigurationProperties(prefix = "batis")
public class BatisProperties {
private String MyClassName;
...
// Make sure you have getters and setter for properties!
// If you use Lombok, put #Data on this class.
...
}
There is no need to explicitly have BatisAutoConfiguration.java. Just let Spring initialize it for you. Completely remove the class BatisAutoConfiguration.java. Also do not use static fields for the property class.
Try the following:
#SpringBootApplication
#EnableAutoConfiguration
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
Or also more explicit, but not needed:
#SpringBootApplication
#ComponentScan(basePackages = {"my.app.org"}) // prefix, where BatisProperties is
#EnableAutoConfiguration
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
or:
#SpringBootApplication
#EnableAutoConfiguration
#Import(BatisProperties.class)
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
The BatisProperties should be available anywhere in your App.
I am implementing custom annotation processing using Spring AOP. I have below code.
public class CacheDemo {
private static ApplicationContext applicationContext;
public static void main(String args[])
{
applicationContext =
new AnnotationConfigApplicationContext(ApplicationConfiguration.class);
}
}
//Application Configuration
#Configuration
#ComponentScan("Demo")
#Component
public class ApplicationConfiguration implements ApplicationContextAware {
#Autowired
TestCacheDemo testCacheDemo;
private static ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext ctx) throws BeansException {
applicationContext = ctx;
}
#Bean
public void testCacheDemoIntialize()
{
testCacheDemo.setApplicationContext(applicationContext);
testCacheDemo.test();
}
}
//CustomAnnotation processor
#Aspect
#Component
public class CustomAnnotationAspect {
#Autowired
private AbstractCacheService cacheService;
#Around("#annotation(Demo.CustomCacheable)")
public Object customCacheable(ProceedingJoinPoint joinPoint) throws Throwable { // This method is not called at all
joinPoint.proceed();
// Some other code to follow
}
// Custom Annotation
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface CustomCacheable {
}
// Annotation user
#Component
public class CacheProvider
{
#Autowired
AbstractCacheService abstractCacheService;
CacheManager<String,String> cacheManager;
#PostConstruct
void init()
{
cacheManager = CreateCache.create(s -> {return s.toUpperCase();});
abstractCacheService.setCacheManager(cacheManager);
}
#CustomCacheable
String getCacheValue(String s)
{
String str=s.toUpperCase();
return str;
}
}
For testing purpose I have created the below bean
#Component
public class TestCacheDemo extends TimerTask
{
private ApplicationContext applicationContext;
private Timer timer;
#Autowired
CacheProvider cacheProvider;
void test()
{
System.out.println("Called test");
for (String beanName : applicationContext.getBeanDefinitionNames()) {
System.out.println(beanName);
}
//CacheProvider cacheProvider = applicationContext.getBean(CacheProvider.class);
//cacheProvider.getCacheValue("Hello");
timer = new Timer();
timer.schedule(this,1000,3000);
}
void setApplicationContext(ApplicationContext ctx)
{
applicationContext=ctx;
}
#Override
public void run() {
cacheProvider.getCacheValue("Hi");
}
}
Whenever the application is started it will call the test method of the TestCacheDemo Class and sets the timer to be fired after 3 secs so that I can call the annotated method getCacheValue from inside the run method of the timer task. But when the annotated method is called the annotation processor is not invoked. Hence I am unable to do annotation processing. Please let me know where is the problem?
To use AspectJ in spring boot you must enable it.
You should add the following annotation to your application main class (CacheDemo) or application configuration class.
#EnableAspectJAutoProxy
I am running springboot application with TimerTask my object of service is showing null.
I have tried various methods but unable to get rid of the Null pointer exception.
main class .
#SpringBootApplication
#ComponentScan(basePackages = {"com.comments.demo"})
public class NotifyMain {
#Autowired
static
NotifyService notifyService;
public static void main(String[] args) {
Timer timer1 = new Timer();
timer1.schedule(notifyService, 10, 10);
SpringApplication.run(NotifyMain.class, args);
}
}
Service class
package com.comments.demo;
#Service
#Configurable
public class NotifyService extends TimerTask{
#Autowired
ListNotification listElement;
#Override
public void run() {
Notification notification= new Notification();
listElement.add(notification);
}
ListNotification and Notification class are working fine.
console
Exception in thread "main" java.lang.NullPointerException
at java.util.Timer.sched(Timer.java:399)
at java.util.Timer.schedule(Timer.java:248)
at com.comments.demo.NotifyMain.main(NotifyMain.java:22)
here is the code of ListNotification
package com.comments.demo;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class ListNotification {
private List<Notification> notifications = new ArrayList<>();
#Autowired
private NotificationObserver notificationObserver;
public void setNotifications(List<Notification> notifications) {
this.notifications = notifications;
}
public void add(Notification notification) {
notifications.add(notification);
notifyListeners(notification);
}
private void notifyListeners(Notification newValue) {
notificationObserver.observation(newValue);
}
}
first I was getting listElement object null. so i got that instead of using the new NotifyService() in parameter of schedule method i should use the injected bean but how to do it I don't know.
You cannot autowire or manually wire static fields in Spring. Instead, try setter injection:
private static NotifyService notifyService;
#Autowired
public void setNotifyService(NotifyService notifyService){
NotifyMain.notifyService= notifyService;
}
But still, there won't be any guarantee if NotifyService is injected before used. You can also try 2nd approach:
private static NotifyService notifyService;
#Autowired
private NotifyService autowiredNotifyService; //same as above but non-static this time. And you autowire this one.
#PostConstruct
private void init() {
NotifyMain.notifyService = this.autowiredNotifyService;
}
3rd Approach -> Use constructor injection:
private static NotifyService notifyService;
#Autowired
public NotifyMain(NotifyService notifyService){
NotifyMain.notifyService= notifyService;
}
Do know that autowiring to static field is undesirable. One should NOT do it.
Since your application is more like a console based application, this approach can also be taken:
#SpringBootApplication
public class NotifyMain implements CommandLineRunner {
#Autowired
private NotifyService notifyService;
public static void main(String[] args) {
SpringApplication.run(NotifyMain.class, args);
}
#Override
public void run(String... args) {
Timer timer1 = new Timer();
timer1.schedule(notifyService, 10, 10);
}
run method inside main class is the starting point of the application. I don't think before starting the application you can autowire objects. try doing this
#SpringBootApplication
public class NotifyMain {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(NotifyMain.class, args);
NotifyService notifyService = (NotifyService) context.getBean(NotifyService.class);
context.getBean(Timer.class).schedule(notifyService, 10, 10);
}
}
Have a look at following code:
#Local
public interface MyService {
void printMessage();
}
#Stateless
public class MyServiceImpl implements MyService {
#Override
public void printMessage() {
System.out.println("Hello from MyService.");
}
}
#Stateless
#Named
public class Application {
#EJB
public MyService sampleService;
private static Application getApplication() throws NamingException {
Properties properties = new Properties();
properties.setProperty(EJBContainer.APP_NAME, "admin");
EJBContainer.createEJBContainer(properties); //.getContext();
Context context = new InitialContext();
Application application = (Application) context.lookup("java:global/admin/classes/Application");
return application;
}
public static void main(String[] args) throws NamingException {
Application application = getApplication();
application.start(args);
}
private void start(String[] args) {
sampleService.printMessage();
}
}
I expected to have simpletService instance available at start() operation, but it is equal to null. All classes are part of one project (placed in separated files). Where I have made mistake? Thanks for advice.
Finally I have found solution. When I changed start() operation to be public and injection started work fine.