NullPointerException при использовании @Autowired - PullRequest
1 голос
/ 08 мая 2020

Я использую picocli, а здесь класс, в котором я перехватываю исключение NPE при попытке teacherService.addTeacher():

@CommandLine.Command
@Component
public class TeacherServiceCommand implements Runnable {

@Autowired
TeacherService teacherService;

 public static void main(String[] args) {
    new TeacherServiceCommand().run();
}

@Override
public void run() {
    AnnotationConfigApplicationContext contextClass = new AnnotationConfigApplicationContext(AppConfig.class);
    ApplicationContext context =
            new ClassPathXmlApplicationContext("applicationContext.xml");
    Teacher teacher = new Teacher(117,"test","test");
    teacherService.addTeacher(teacher);
}

AppConfig.class:

@Configuration
@ComponentScan("com.foxminded.uviversity")
@PropertySource("classpath:db.properties")
public class AppConfig {
 private static final String URL = "URL";
private static final String USER = "USER";
private static final String DRIVER = "DRIVER";
private static final String PASSWORD = "PASSWORD";

@Autowired
Environment environment;

 @Bean
DataSource dataSource() {
    DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
    driverManagerDataSource.setUrl(environment.getProperty(URL));
    driverManagerDataSource.setUsername(environment.getProperty(USER));
    driverManagerDataSource.setPassword(environment.getProperty(PASSWORD));
    driverManagerDataSource.setDriverClassName(environment.getProperty(DRIVER));
    return driverManagerDataSource;
}


@Bean
TeacherService teacherService(DataSource dataSource) {
    return new TeacherServiceImpl(dataSource);
}
}

TeacherService - это интерфейс.

TeacherServiceImpl реализует TeacherService:

@Component
public class TeacherServiceImpl implements TeacherService {
 private static final String SQL_INSERT_TEACHER = "INSERT INTO teachers(teacher_id, teacher_name, position) VALUES (?,?,?)";

JdbcTemplate jdbcTemplate;

@Autowired
public TeacherServiceImpl(DataSource dataSource) {
    jdbcTemplate = new JdbcTemplate(dataSource);
}


@Override
public boolean addTeacher(Teacher teacher) {
    return jdbcTemplate.update(SQL_INSERT_TEACHER, teacher.getTeacherId(), teacher.getTeacherName(), teacher.getPosition()) > 0;
}

Может, где-то меня запутали аннотации или что-то в этом роде. Заранее благодарим за каждую помощь!

applicationContext.xml  

файл предназначен только для инициализации базы данных.

    <jdbc:initialize-database>
    <jdbc:script location="classpath:schema.sql"/>
</jdbc:initialize-database>

Я запускаю SQL скрипт для создания таблиц в application.xml.

Если вы знаете, как инициализировать базу данных через аннотации, буду благодарен!

Full stacktrace:

May 08, 2020 10:18:08 AM org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@433c675d: startup date [Fri May 08 10:18:08 EEST 2020]; root of context hierarchy
May 08, 2020 10:18:08 AM org.springframework.beans.factory.support.DefaultListableBeanFactory registerBeanDefinition
INFO: Overriding bean definition for bean 'teacherService' with a different definition: replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=universityConfiguration; factoryMethodName=teacherService; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [com/foxminded/university/UniversityConfiguration.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=appConfig; factoryMethodName=teacherService; initMethodName=null; destroyMethodName=(inferred); defined in com.foxminded.university.config.AppConfig]
May 08, 2020 10:18:08 AM org.springframework.jdbc.datasource.DriverManagerDataSource setDriverClassName
INFO: Loaded JDBC driver: org.postgresql.Driver
May 08, 2020 10:18:08 AM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@78dd667e: startup date [Fri May 08 10:18:08 EEST 2020]; root of context hierarchy
May 08, 2020 10:18:08 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [applicationContext.xml]
May 08, 2020 10:18:09 AM org.springframework.beans.factory.support.DefaultListableBeanFactory registerBeanDefinition
INFO: Overriding bean definition for bean 'teacherService' with a different definition: replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=appConfig; factoryMethodName=teacherService; initMethodName=null; destroyMethodName=(inferred); defined in com.foxminded.university.config.AppConfig] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=universityConfiguration; factoryMethodName=teacherService; initMethodName=null; destroyMethodName=(inferred); defined in com.foxminded.university.UniversityConfiguration]
May 08, 2020 10:18:09 AM org.springframework.jdbc.datasource.DriverManagerDataSource setDriverClassName
INFO: Loaded JDBC driver: org.postgresql.Driver
May 08, 2020 10:18:09 AM org.springframework.jdbc.datasource.init.ScriptUtils executeSqlScript
INFO: Executing SQL script from class path resource [schema.sql]
May 08, 2020 10:18:10 AM org.springframework.jdbc.datasource.init.ScriptUtils executeSqlScript
INFO: Executed SQL script from class path resource [schema.sql] in 1162 ms.
Exception in thread "main" java.lang.NullPointerException
    at com.foxminded.university.cli.TeacherServiceCommand.run(TeacherServiceCommand.java:44)
    at com.foxminded.university.cli.TeacherServiceCommand.main(TeacherServiceCommand.java:32)

Stacktrace after removing `teacherService` bean creation from `AppConfig` and marked `TeacherServiceImpl`with annotation `@Service` :

May 08, 2020 10:58:09 AM org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@433c675d: startup date [Fri May 08 10:58:09 EEST 2020]; root of context hierarchy
May 08, 2020 10:58:10 AM org.springframework.jdbc.datasource.DriverManagerDataSource setDriverClassName
INFO: Loaded JDBC driver: org.postgresql.Driver
May 08, 2020 10:58:10 AM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@290d210d: startup date [Fri May 08 10:58:10 EEST 2020]; root of context hierarchy
May 08, 2020 10:58:10 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [applicationContext.xml]
May 08, 2020 10:58:10 AM org.springframework.jdbc.datasource.DriverManagerDataSource setDriverClassName
INFO: Loaded JDBC driver: org.postgresql.Driver
May 08, 2020 10:58:10 AM org.springframework.jdbc.datasource.init.ScriptUtils executeSqlScript
INFO: Executing SQL script from class path resource [schema.sql]
May 08, 2020 10:58:11 AM org.springframework.jdbc.datasource.init.ScriptUtils executeSqlScript
INFO: Executed SQL script from class path resource [schema.sql] in 1108 ms.
Exception in thread "main" java.lang.NullPointerException
    at com.foxminded.university.cli.TeacherServiceCommand.run(TeacherServiceCommand.java:49)
    at com.foxminded.university.cli.TeacherServiceCommand.main(TeacherServiceCommand.java:36) 

Ответы [ 2 ]

2 голосов
/ 08 мая 2020

Вместо прямого вызова метода run

 public static void main(String[] args) {
    new TeacherServiceCommand().run();
}

Чтобы использовать picocli для синтаксического анализа аргументов командной строки, вам необходимо создать объект picocli.CommandLine и вызвать его метод execute. Чтобы внедрить службы Spring, используйте PicocliSpringFactory из модуля picocli-spring-boot-starter.

import org.springframework.context.ApplicationContext;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.spring.PicocliSpringFactory;

@Command(name = "teacherservice", mixinStandardHelpOptions = true)
@Component
public class TeacherServiceCommand implements Runnable {

  @Autowired
  TeacherService teacherService;

  public static void main(String[] args) {
    AnnotationConfigApplicationContext contextClass = new AnnotationConfigApplicationContext(AppConfig.class);
    ApplicationContext context =
            new ClassPathXmlApplicationContext("applicationContext.xml");

    new CommandLine(TeacherServiceCommand.class, new PicocliSpringFactory(context))
        .execute(args); // this calls run after parsing the command line args
  }

  @Override
  public void run() {
    Teacher teacher = new Teacher(117,"test","test");
    teacherService.addTeacher(teacher);
  }
}

См. Также https://github.com/remkop/picocli/tree/master/picocli-spring-boot-starter для получения дополнительных сведений и примеров.

0 голосов
/ 08 мая 2020

Это может быть связано с

new TeacherServiceCommand().run();

вместо автоподключения TeacherService. Можете ли вы получить его из контекста Spring внутри метода run, как показано ниже, и посмотреть, поможет ли это.

TeacherService teacherService = context.getBean(TeacherService.class);
...