Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

picocli Option of type collection gets injected with another bean, when using Spring integration #2352

Open
marco-brandizi opened this issue Nov 27, 2024 · 4 comments

Comments

@marco-brandizi
Copy link

marco-brandizi commented Nov 27, 2024

I've written a CLI tool leveraging Spring-based code that I already had. I followed this example to arrange it, I'm using picocli-spring-boot-starter 4.7.6 and it mostly works, except for this in the @Command class:

@Option (
	names = { "-s", "--tax-ids" },
	paramLabel = "<NCBITaxId>",
	description = "The TAXIDs of the seed genes (space or comma-separated)",
	split = "[\\s,\\,]",
	splitSynopsisLabel = " "
)
private Set<String> taxIds = null; 

In the application, there is another bean of type Set, but marked with a different generic, something like:

@Configuration
public class MyConfig
{
  @Bean ( "myElements" )
  public Set<MyElem> getMyElements () {...}
}

@Component
public class MyComponent
{
  @Autowired @Qualifier ( "myElements" )
  private Set<MyElem> myElements;
  ...
}

Without picocli, everything works fine and Spring binds getMyElements() to myElements, even without bean name and qualifier, which I've introduced in the hope to fix the problem I'm reporting.

When I try to use picocli as above, the console output clearly shows me that taxId got populated with the union of --tax-id arguments coming from the invocation PLUS objects in myElements. In fact, the application fails with a ClassCastException.

I'm already aware that generics cause this kind of issue to Spring, and I would try another qualifier alongside the picocli option, but there isn't any explicit Spring annotation there.

The only workaround I've found so far is declaring the picocli option as a list and turning it into a set in the command execution. While this works, I'm quite concerned about when I'll need to add another bean of type List...

A different thing I've tried is @Option.type = String.class, with no luck.

@remkop
Copy link
Owner

remkop commented Nov 27, 2024

Hm, maybe the SpringFactory in the picocli-spring-boot module can be enhanced.
Have you tried playing with creating different implementations for that factory? Let me know what you find!

@marco-brandizi
Copy link
Author

marco-brandizi commented Nov 28, 2024

Hi @remkop, thanks for your reply. Sorry, not sure I get you, the only IFactory implementation I see that integrates with Spring wiring is PicocliSpringFactory.

@remkop
Copy link
Owner

remkop commented Nov 30, 2024

Yes. I guess my question is, how would you enhance picocli to improve your use case?

@marco-brandizi
Copy link
Author

marco-brandizi commented Dec 2, 2024

Yes. I guess my question is, how would you enhance picocli to improve your use case?

To answer that, I should get how an ApplicationContext field/bean is mixed with @Option field, which, seems to be the root cause of the problem. When I use Spring only, a way to avoid these clashes is @Qualifier, but here, mixing picocli and Spring annotations doesn't seem possible. Maybe the picocli PicocliSpringFactory could leverage @Option.type to filter the proper beans in cases like this?

Defining specific classes that extend collections might be another workaround (as per the already mentioned case), but this would not be so practical.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants