question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Feature suggestion: allow non-static inner classes to be subcommands of their outer class

See original GitHub issue

For example, something like (not tested)

@Command(name="outer", subcommands={Inner.class})
public class Outer {

    @Command(name="inner")
    public class Inner {}
}

Currently this doesn’t work, since Inner requires an instance of Outer. Would it be possible to make it so that when an instance of Outer is run via the CommandLine it will create an instance of Inner and use it as a subcommand? This would probably only really work if Inner is a subcommand of Outer, as opposed to a subcommand of a completely separate class.

I know Inner could be made static, but then it loses the ability to use private variables of Outer, which is useful. Another possible way to do something like this (which I have not tested) might be to use a method as the command and have it run a new Inner object with all args it recieves. But even if that would work (and I’m not sure), it would be simpler to be able to be able to just put it in the subcommands section.

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:7 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
BeeeWallcommented, Feb 2, 2019

That makes sense, fair enough.

0reactions
remkopcommented, Feb 2, 2019

I’ve given it some thought (thanks for the PR in #621 that made it very concrete what you had in mind) but I’m leaning against doing this, for three reasons.

There is an alternative

You can use a static inner class and still access the private variables of the outer class, using the @ParentCommand annotation:

@Command(name="outer", subcommands={Inner.class})
public class Outer {
    private int privateVariable;

    @Command(name="inner")
    public static class Inner {
        @ParentCommand Outer outer; // injected by picocli 

        public void businessLogic() {
            doSomethingWith(outer.privateVariable);
        }
    }
}

Making InnerClassFactory the default factory would not always work

For example, there are the static methods like the below, where a class is passed in, and there is no instance of the outer class available. Non-static inner class commands would work with other API calls but would result in runtime exceptions with these methods. This would surprise some users which we should avoid.

public static <C extends Callable<T>, T> T call(Class<C> callableClass, IFactory factory, String... args)
public static <R extends Runnable> void run(Class<R> runnableClass, IFactory factory, String... args)

There may be other edge cases where InnerClassFactory does not work, I haven’t looked in detail. I imagine there may be a problem if command hierarchy has several levels of non-static inner class commands: we pass in an instance of the top-most class, but another instance would be needed for the class that is nested inside the inner class…

I prefer to keep the contract of IFactory simple

If the default implementation can handle non-static inner classes then in practice users will expect that capability from all factory implementations. I think this is demanding too much for other implementors.

The factory is mainly intended for integration with dependency injection frameworks like Micronaut or Spring Boot, where the DI framework is responsible for creating instances (which themselves may have services injected into them by the DI framework).

The current default factory is straightforward and can easily be replaced by one that integrates with the dependency injection framework, see for example the Guice example from the picocli documentation.

If we replaced the current simple default factory with a more powerful one that also handles inner classes, that would make integration with dependency injection frameworks more difficult which would defeat the purpose.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Nested Classes - Learning the Java Language
Terminology: Nested classes are divided into two categories: non-static and static. Non-static nested classes are called inner classes. Nested classes that are ...
Read more >
Java static code analysis: Inner classes which do not ...
A non-static inner class has a reference to its outer class, and access to the outer class' fields and methods. That class reference...
Read more >
How Java Static Nested Class Works? - eduCBA
Static inner classes is a nested class. This class is present as a static member under any class that acts as an outer...
Read more >
Difference Between Static and Non Static Nested Class in Java
The class which enclosed nested class is known as Outer class. In the Java programming language, you can not make a top-level class...
Read more >
Java inner class and static nested class - Stack Overflow
Inner classes have access to instance variables of the enclosing instance of the Outer [parent] class. However, not all inner classes have enclosing...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found