Search code examples
javaspring-bootdaodiscord-jda

Constructor Injection together with JDA and Spring Boot


I am struggling with initializing JDA as the "addEventListeners" requires me to input the EventListeners.. However, my EventListeners have "injected constructors" (if that's the correct word) that is grabbing my Dao's.

I would gladly use @Autowire in my EventListeners, but it keeps on giving me a NullPointer.

I think the issue is that JDA extends their EventListener, which basically loads outside of Spring Boot, even though I've added the @Service annotation on the Listener.

You can see my problem below at: .addEventListeners(new JDAEventListener())

Obviously, I am not able to do new JDAEventListener()as it requires the WixSubscriptionDao. However, I am not able to understand how to initiate the JDAEventListener without WixSubscriptionDao, as I need the Dao for further data handling.

public static void main(String[] args) throws InterruptedException, LoginException {

    JDA jda = JDABuilder.createDefault("XXXXXXXXXXXXXXXXXXXXXX")
            .enableIntents(GatewayIntent.GUILD_MESSAGES, GatewayIntent.GUILD_MEMBERS)
            .setChunkingFilter(ChunkingFilter.ALL)
            .setMemberCachePolicy(MemberCachePolicy.ALL)
            .addEventListeners(new JDAEventListener())
            .build();
    DISCORD_CONSTANT.jda = jda.awaitReady();
    setupDefault();
}
@Service
public class JDAEventListener implements EventListener {

    private final WixSubscriptionDao wixSubscriptionDao;

    public JDAEventListener(WixSubscriptionDao wixSubscriptionDao) {
        this.wixSubscriptionDao = wixSubscriptionDao;
    }

    @Override
    public void onEvent(@NotNull GenericEvent genericEvent) {
        if (genericEvent instanceof ReadyEvent) {
            System.out.println("ReadyEvent done");
            ArrayList<WixSubscription> wixSubscriptions = wixSubscriptionDao.findAll();
            System.out.println(wixSubscriptions.size());
    }
}

I would love to do this, but as wrote above, the @Autowired Dao is giving me a NullPointer, even though it's defined in the SpringConfig. (The DAO works perfectly when using the constructor method)

@Service
public class JDAEventListener implements EventListener {

    @Autowired
    private WixSubscriptionDao wixSubscriptionDao;

    public JDAEventListener() {
    }

    @Override
    public void onEvent(@NotNull GenericEvent genericEvent) {
        if (genericEvent instanceof ReadyEvent) {
            System.out.println("ReadyEvent done");
            ArrayList<WixSubscription> wixSubscriptions = wixSubscriptionDao.findAll();
            System.out.println(wixSubscriptions.size());
        }
}

Solution

  • I suggest that you create class annotated with @Component which implements CommandLineRunner interface. This means that, the run method will be executed when the application starts. Also, you can inject other Spring beans into it, like for example JDAEventListener beans.

    @Component
    public class JDAInitializer implements CommandLineRunner {
        private final JDAEventListener jdaEventListener;
        
        // Constructor injection
        public JDAInitializer(JDAEventListener jdaEventListener) {
            this.jdaEventListener = jdaEventListener;
        }
    
        @Override
        public void run(String... args) throws Exception {
            JDA jda = JDABuilder.createDefault("XXXXXXXXXXXXXXXXXXXXXX")
                    .enableIntents(GatewayIntent.GUILD_MESSAGES, GatewayIntent.GUILD_MEMBERS)
                    .setChunkingFilter(ChunkingFilter.ALL)
                    .setMemberCachePolicy(MemberCachePolicy.ALL)
                    .addEventListeners(jdaEventListener)
                    .build();
            DISCORD_CONSTANT.jda = jda.awaitReady();
            setupDefault();
        }
    
     ...
    }