I have a service which needs to create Agents on the runtime. Agents inherit from a base Agent class. I would like to use the Autowired ability of spring instead of doing my own dependency injections.
But I am running into this issue, even though I am marking the component as scope=prototype, and even @Lazy to prevent anything from happening at compile-time.
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in com.my.project.AgentType1 required a bean of type 'com.my.project.POJO' that could not be found.
This is the service that tries to create the agents:
@Service
public class ProjectMain {
@Autowired
ApplicationContext context;
List<IAgent> agents = new ArrayList<>();
void SetupAgents(List<POJO> agentPojos) {
for(POJO agentPojo: agentPojos) {
IAgent agent = AgentFactory.CreateAgent(agentPojo, context);
agents.add(agent);
}
}
}
This is the factory class, not marked as @Component etc. It uses the context passed to it to create the child class beans. It tries to pass the constructor argument via the getBean method.
public class AgentFactory {
public static IAgent CreateAgent(POJO agentPojo, ApplicationContext context) {
if (agentPojo.type.equals("AgentType1")) {
return context.getBean(AgentType1.class, agentPojo);
} else {
return context.getBean(AgentType2.class, agentPojo);
}
}
}
This is a custom annotation which I found is needed for inheritance scenarios.
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Component
@Inherited
@Lazy
@Scope("prototype")
public @interface AgentAnnotation {}
These are the base and child agent classes, which need a custom data structure called POJO to work.
@AgentAnnotation
public class BaseAgent implements IAgent {
@Autowired
Environment env;
public BaseAgent(POJO agentPojo, String someotherdata) {
}
}
public class AgentType1 extends BaseAgent {
public AgentType1(POJO agentPojo) {
super(agentPojo, "mydata1");
...
}
}
public class AgentType2 extends BaseAgent {
public AgentType2(POJO agentPojo) {
super(agentPojo, "mydata2");
...
}
}
This is the starter app.
@ComponentScan(basePackages = "com.my.project", includeFilters = @ComponentScan.Filter(AgentAnnotation.class))
@EnableScheduling
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
I also tried the configuration approach:
@Configuration
public class BaseAgentConfig {
@Bean
@Scope("prototype")
public AgentType1 agentType1(POJO agentPojo) {
return new AgentType1(agentPojo);
}
@Bean
@Scope("prototype")
public AgentType2 agentType2(POJO agentPojo) {
return new AgentType2(agentPojo);
}
}
In this case, I removed the @AgentAnnotation from the baseAgent class as we are now instantiating through this config. Also removed the ComponentScan line from the main App.
This time around, the @Autowired doesn't work. All Autowired references in the baseAgent class are null.
Please advise on the best approach to solve this error. Thanks.