Столкновение с NullPointerException при попытке внедрить репозиторий в приложение весенней загрузки

Я пытаюсь реализовать функцию уведомления в своем приложении.

Вариант использования:

  • Когда будет создана новая глава, пользователи, подписавшиеся на этот роман, получат уведомление.

Проблема:

  • Но я продолжаю получать NullPointerException за NotificationRepository, хотя я пробовал такие вещи, как аннотация @Autowired, передача параметра метода и т. д., чтобы это работало, но это не работает вообще. Я не знаю, в чем основная причина.

У меня есть класс ChapterService, который уведомляет пользователей о создании новой главы.

@Service
public class ChapterService extends BaseService<Chapter, ObjectId, ChapterDTO>{
    @Autowired
    protected Mapper<ChapterDTO, Chapter> mapper;

    private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);

    public ChapterDTO create(ChapterDTO chapterDTO) {
        Chapter chapter = mapper.convertToEntity(chapterDTO);
        Chapter savedChapter = repository.save(chapter);
        notifySubscribers(savedChapter, savedChapter.getNovelName());
        return mapper.convertToDTO(savedChapter);
    }

    public void addPropertyChangeListener(PropertyChangeListener listener) {
        propertyChangeSupport.addPropertyChangeListener(listener);
    }

    public void removePropertyChangeListener(PropertyChangeListener listener) {
        propertyChangeSupport.removePropertyChangeListener(listener);
    }

    private void notifySubscribers(Chapter newChapter, String novelName) {
        for (PropertyChangeListener listener : propertyChangeSupport.getPropertyChangeListeners()) {
            if (listener instanceof NovelSubscriber && ((NovelSubscriber) listener).getNovelName().equals(novelName)) {
                listener.propertyChange(new PropertyChangeEvent(this, "chapter", null, newChapter));
            }
        }
    }

У меня есть класс NovelSubscriber, который определяет отношения между романом и пользователем. Новая запись была создана, когда пользователь подписался на этот роман, и приведенная ниже логика изменится и отправит уведомление соответствующим пользователям.

@Document(collection = "subscribers")
@Data
public class NovelSubscriber implements PropertyChangeListener{
    @Id
    private ObjectId id;
    private ObjectId userId;
    private String novelName;

    private NotificationService notificationService;
    protected static final Logger logger = LoggerFactory.getLogger(NovelSubscriber.class);

    public NovelSubscriber(ObjectId userId, String novelName, NotificationService notificationService) {
        this.userId = userId;
        this.novelName = novelName;
        this.notificationService = notificationService;
    }

    @Override
    public void propertyChange(PropertyChangeEvent event) {
        if (event.getPropertyName().equals("chapter")) {
            Chapter newChapter = (Chapter) event.getNewValue();
            sendNotification(newChapter);
        }
    }

    private void sendNotification(Chapter newChapter) {
        notificationService.sendNotification(userId, novelName + " have 1 new chapter: " + newChapter.getChapterTitle());
    }
}

Вот NovelSubscriberService

@Service
public class NovelSubscriberService{
    @Autowired
    ChapterService chapterService;

    @Autowired
    NotificationService notificationService;

    @Autowired
    NovelSubscriberRepository subscriberRepository;

    private List<NovelSubscriber> subscribers = new ArrayList<>();

    @PostConstruct
    public void init() {
        loadSubscribers();
    }

    private void loadSubscribers(){
        subscribers = subscriberRepository.findAll();
        for (NovelSubscriber subscriber : subscribers) {
            chapterService.addPropertyChangeListener(subscriber);
        }
    }

    public void subscribe(String userId, String novelName) {
        NovelSubscriber subscriber = new NovelSubscriber(new ObjectId(userId), novelName, notificationService);
        NovelSubscriber savedNovelSubscriber = subscriberRepository.save(subscriber);
        chapterService.addPropertyChangeListener(savedNovelSubscriber);
    }

    public void unsubscribe(String userId, String novelName) throws ItemNotFoundException {
        NovelSubscriber subscriber = findByUserIdAndNovelName(new ObjectId(userId), novelName);
        chapterService.removePropertyChangeListener(subscriber);
        subscriberRepository.delete(subscriber);
    }

    private NovelSubscriber findByUserIdAndNovelName(ObjectId userId, String novelName) throws ItemNotFoundException {
        return subscriberRepository
                    .findByUserIdAndNovelName(userId, novelName)
                    .orElseThrow(() -> new ItemNotFoundException("Subscriber not found"));
    }

}

Вот NotificationService

@Service
public class NotificationService{
    @Autowired
    protected MongoRepository<Notification, ObjectId> repository; // Use MongoRepository

    @Autowired
    Mapper<NotificationDTO, Notification> mapper;

    protected static final Logger logger = LoggerFactory.getLogger(NotificationService.class);

    public void sendNotification(ObjectId userId, String content) {

        if (repository == null) {
            logger.error("repository is null new");
        }

        Notification notification = makeNewNotification(userId, content);
        repository.save(notification);
    }

    public List<NotificationDTO> findByUserIdAndIsSeenFalse(ObjectId userId) 
                                    throws InterruptedException{
        logger.debug("Finding Notifications");

        List<Notification> notifications = ((NotificationRepository) repository).findByUserIdAndIsSeenFalse(userId);

        logger.debug("Found Notifications: {}", notifications);
        return convertToDTOs(notifications);
    }

    public NotificationDTO update(String id) throws ItemNotFoundException {
        logger.debug("change notifcation state");
    
        Notification notification = changeNoticationState(id);
        Notification updatedNotification = repository.save(notification);
        logger.debug("Updated Notification successfully: {}", updatedNotification);
    
        return mapper.convertToDTO(updatedNotification);
    }

    private Notification changeNoticationState(String id) throws ItemNotFoundException {
        Notification notification = findById(new ObjectId(id));
        notification.setSeen(true);
        return notification;
    }

    private List<NotificationDTO> convertToDTOs(List<Notification> notifications) {
        return notifications.stream()
                .map(mapper::convertToDTO)
                .collect(Collectors.toList());
    }

    private Notification makeNewNotification(ObjectId userId, String content) {
        return Notification.builder()
            .userId(userId)
            .content(content)
            .sentAt(LocalDate.now())
            .build();
    }

    private Notification findById(ObjectId id) throws ItemNotFoundException {
        return repository.findById(id).orElseThrow(() -> new ItemNotFoundException("Notification not found"));
    }
}

Вот NotificationRepository

@Repository
public interface NotificationRepository extends MongoRepository<Notification, ObjectId> {
    @Query(NotificationQueries.FIND_BY_USER_ID_AND_IS_SEEN_FALSE)
    List<Notification> findByUserIdAndIsSeenFalse(ObjectId userId);
}

Вот журнал ошибок:

java.lang.NullPointerException: Cannot invoke \"org.springframework.data.mongodb.repository.MongoRepository.save(Object)\" because \"this.repository\" is null\r
    at com.example.novelWebsite.service.serviceimpl.NotificationService.sendNotification(NotificationService.java:37)\r
    at com.example.novelWebsite.model.NovelSubscriber.sendNotification(NovelSubscriber.java:49)\r
    at com.example.novelWebsite.model.NovelSubscriber.propertyChange(NovelSubscriber.java:44)\r
    at com.example.novelWebsite.service.serviceimpl.ChapterService.notifySubscribers(ChapterService.java:48)\r
    at com.example.novelWebsite.service.serviceimpl.ChapterService.create(ChapterService.java:33)\r
    at com.example.novelWebsite.controller.controllerimpl.ChapterController.create(ChapterController.java:65)

Вот NovelSubscriberController

@RestController
@RequestMapping("/api/subscribers")
public class NovelSubscriberController {
    private static final Logger logger = LoggerFactory.getLogger(NovelSubscriberController.class);

    @Autowired
    private NovelSubscriberService novelSubscriberService;

    @PostMapping("/{userId}/{novelName}")
    public ResponseEntity<?> subscribe(@PathVariable String userId, @PathVariable String novelName) {
        try {
            novelSubscriberService.subscribe(userId, novelName);
            logger.info("User {} subscribed to novel {}", userId, novelName);
            return new ResponseEntity<>(HttpStatus.OK);
        } catch (Exception e) {
            logger.error("Error when subscribing user to novel", e.getMessage());
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());
        }
    }

    @DeleteMapping
    public ResponseEntity<?> unsubscribe(@RequestParam String userId, @RequestParam String novelName) {
        try {
            novelSubscriberService.unsubscribe(userId, novelName);
            logger.info("User {} unsubscribed from novel {}", userId, novelName);
            return new ResponseEntity<>(HttpStatus.OK);
        } catch (ItemNotFoundException e) {
            logger.error("Error when unsubscribing user from novel", e.getMessage());
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());
        }
    }
}

Вот ChapterController

@RestController
@RequestMapping("/api/chapters") 
public class ChapterController  implements BaseController{
    private static final Logger logger = LoggerFactory.getLogger(ChapterController.class);

    @Autowired
    private BaseService<Chapter, ObjectId, ChapterDTO> chapterService;

    @GetMapping("/{novelName}/{chapterNumber}") 
    public ResponseEntity<?> findByNovelNameAndChapterNumber(@PathVariable String novelName, @PathVariable Integer chapterNumber){
        try {
            ChapterDTO chapterDTO = ((ChapterService) chapterService)
                        .findByNovelNameAndChapterNumber(novelName, chapterNumber);
            logger.info("finding chapter");
            return new ResponseEntity<>(chapterDTO, HttpStatus.OK);
        } 
        catch (InterruptedException | ItemNotFoundException e) {
            logger.error("Error when finding chapter", e.getMessage());
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());
        }
    }

    @GetMapping("/{novelName}") 
    public ResponseEntity<?> findOverviewsByNovelName(@PathVariable String novelName){
        try {
            List<ChapterOverviewDTO> chapterOverviewDTOs = ((ChapterService) chapterService)
                        .findOverviewsByNovelName(novelName);
            logger.info("finding chapter overview");
            return new ResponseEntity<>(chapterOverviewDTOs, HttpStatus.OK);
        } 
        catch (InterruptedException e) {
            logger.error("Error when finding chapter", e.getMessage());
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());
        }
    }

    @PostMapping 
    public ResponseEntity<?> create(@RequestBody ChapterDTO chapterDTO) {
        ((ChapterService) chapterService).create(chapterDTO);
        logger.info("creating chapter");
        return new ResponseEntity<>(HttpStatus.OK);
    }

    @PutMapping 
    public ResponseEntity<?> update(@RequestBody ChapterDTO chapterDTO) {
        try {
            ((ChapterService) chapterService).update(chapterDTO);
            logger.info("Updating chapter: {}", chapterDTO);
            return new ResponseEntity<>(HttpStatus.OK);  
        } 
        catch (ItemNotFoundException e) {
            logger.error("Error when updating chapter");
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());
        }
    }

    @PutMapping("/enable/{id}") 
    public ResponseEntity<?> enableChapter(@PathVariable String id)  {
        try {
            ((ChapterService) chapterService).enableChapter(id);
            logger.info("Enabling chapter");
            return new ResponseEntity<>(HttpStatus.OK);
        } 
        catch (ItemNotFoundException e) {
            logger.error("Error when enabling chapter", e.getMessage());
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());
        }
    }

    @PutMapping("/disable/{id}") 
    public ResponseEntity<?> disableChapter(@PathVariable String id){
        try {
            ((ChapterService) chapterService).disableChapter(id);
            logger.info("disabling chapter");
            return new ResponseEntity<>(HttpStatus.OK);
        } 
        catch (ItemNotFoundException e) {
            logger.error("Error when disabling chapter", e.getMessage());
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());
        }
    }
}

К вашему сведению, я уже пробовал такие вещи, как @Autowired, передавать по параметру notificationRepository везде в notificationService, novelSubscriber, но журнал продолжает показывать null для репозитория, хотя глава была создана.

Я был бы признателен за любую помощь в этом вопросе.

Добавьте свой контроллер.

M. Deinum 12.08.2024 09:54

я только что сделал, спасибо за помощь

nino144 12.08.2024 10:00
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
2
51
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы передаете управляемый Spring bean-компонент в bean-компонент, не управляемый Spring, что и вызывает проблему.

Эта строка представляет собой проблему, приведенную ниже.

NovelSubscriber subscriber = new NovelSubscriber(new ObjectId(userId), novelName, notificationService);

Spring DI не будет работать в таком сценарии.

Чтобы Spring DI работал, каждый объект должен управляться Spring.

Спасибо, это сработало! Мне удалось это исправить, передав NotificationService в качестве параметра в propertyChangeEvent. Извините за поздний ответ; Я был занят и не смог вчера проверить ошибку

nino144 14.08.2024 04:04

Другие вопросы по теме