Closed Taz03 closed 1 month ago
What about a different approach? Doing something like autowired is crazy complex and we're really deep into our own code to now swap it for a DI framework (those are very very big).
What about a more pragmatic approach?
E.g. we can have a global static map that you can store instances of objects inside e.g.
static Map<Class, Object> objectsMap;
Then inside the listener, we can do
MyClass instance = (MyClass) objectsMap.get(MyClass.class);
Or if we know a way, we can use an Annotation to inject the instance?
@Taz03 here I added this to my PR: https://github.com/javadiscord/java-discord-api/pull/148/commits/c1acab7c548b3baf2e207e8aa5f6e056d4274ced
The way it works is you create any static builder for example:
@Component
public static ChatGPT chatGpt() {
return new ChatGPT();
}
Add this anywhere into project and make sure it's static
! If it's not static, we have to initalize the parent class. That means we would have to either tell the user to have a 0-arg constructor or we figure out the parameters. Not good. Using static makes it really simple.
Next, we can reference this component anywere in classes that use @SlashCommand
or @EventListener
.
Like this:
@Inject
private ChatGPT chatGPT;
@Taz03 here I added this to my PR: c1acab7
The way it works is you create any static builder for example:
@Component public static ChatGPT chatGpt() { return new ChatGPT(); }
Add this anywhere into project and make sure it's
static
! If it's not static, we have to initalize the parent class. That means we would have to either tell the user to have a 0-arg constructor or we figure out the parameters. Not good. Using static makes it really simple.Next, we can reference this component anywere in classes that use
@SlashCommand
or@EventListener
.Like this:
@Inject private ChatGPT chatGPT;
What if this component like chatgpt in this case needs some other component or data in general? How do you provide it?
@Taz03 here I added this to my PR: c1acab7 The way it works is you create any static builder for example:
@Component public static ChatGPT chatGpt() { return new ChatGPT(); }
Add this anywhere into project and make sure it's
static
! If it's not static, we have to initalize the parent class. That means we would have to either tell the user to have a 0-arg constructor or we figure out the parameters. Not good. Using static makes it really simple. Next, we can reference this component anywere in classes that use@SlashCommand
or@EventListener
. Like this:@Inject private ChatGPT chatGPT;
What if this component like chatgpt in this case needs some other component or data in general? How do you provide it?
The method annotated with @Component
is just a static getter.
Currently, the way it works is, the codebase scans for all @Component
in the class path. It will then invoke it so we can have the instance.
Next, when we load the @EventListener
and @SlashCommand
, after we create the object, we inject any @Component
objects we created into the fields that have @Inject
and that's all good to go.
The problem that is being solved is @EventListener
having a requirement of 0 arg-constructor. We can additionally, use @Inject
on a constructor too if this is something we want implemented.
The method annotated with
@Component
is just a static getter.Currently, the way it works is, the codebase scans for all
@Component
in the class path. It will then invoke it so we can have the instance.Next, when we load the
@EventListener
and@SlashCommand
, after we create the object, we inject any@Component
objects we created into the fields that have@Inject
and that's all good to go.
The problem that is being solved is
@EventListener
having a requirement of 0 arg-constructor. We can additionally, use@Inject
on a constructor too if this is something we want implemented.
I doubt that answers my question. What if the component itself got dependencies. Using the chatgpt component as an example: Imagine you want to load the key from a config file and then use it in the chatgpt constructor itself. How are you going to do that?
The method annotated with
@Component
is just a static getter. Currently, the way it works is, the codebase scans for all@Component
in the class path. It will then invoke it so we can have the instance. Next, when we load the@EventListener
and@SlashCommand
, after we create the object, we inject any@Component
objects we created into the fields that have@Inject
and that's all good to go. The problem that is being solved is@EventListener
having a requirement of 0 arg-constructor. We can additionally, use@Inject
on a constructor too if this is something we want implemented.I doubt that answers my question. What if the component itself got dependencies. Using the chatgpt component as an example: Imagine you want to load the key from a config file and then use it in the chatgpt constructor itself. How are you going to do that?
I see the misunderstanding, so the point of the @Component
being part of a static method is because we then do not need to instaniate the object ourselves. Here's an example:
public class Main {
private static ChatGpt chatGpt;
public static void main(String[] args) {
chatGpt = new ChatGpt(args);
}
@Component
public static ChatGpt chatgpt() {
return chatgpt;
}
}
In this example, the ChatGpt object is being created by the user (in my example, the main method).
This is how I would expect other people to setup their components, they can do it anywhere and in any class. As long as all the objects are ready and created before they call discord.start()
.
We have to remember, we are not creating a general purpose DI framework. We are supporting a very specific usecase which is just passing an instance to our @EventListener
and @SlashCommand
classes. If the end user wants to do more than that then they should use a DI framework of their choice.
The only annotations we support are @Inject
and @Component
. We have no further need to be able to provide more flexibility. There just isn't a requirement for this or a real usecase for it when it comes to this discord framework.
Some DI frameworks have annotations like @Factory
- we don't need this! Our @EventListeners
are singleton. Since we create the entire lifecycle of these objects as they are our own. Our framework creates and manages them. They are only entry points to discord events for the user to write their code inside.
Can we support further functionality? Of course, if we want to add @Inject
on constructors for example, we deffo can, it won't take more than 5-10mins to implement.
If we don't want singleton Components
we don't have to but we first need to identify the problem before we implement a soluton.
Once again, remember, we are not creating a general purpose DI framework and any extra functionality that a user might want or need, they can introduce on their own by adding the relevant libraries to their builds.
Right now if a class annotated with
@EventListener
has a non no-args constructor it is not considered a valid EventListener.A possible solution would be to integrate it with a DI framework, and automatically initialize all classes annotated with
EveneListener
with Autowired params