At the risk of sounding incredibly stupid and receiving a rather patronising answer, how do I view all other classes that extend the current 'viewed class' in javadocS?
i.e.
Object a {}
Object b extends a {}
Viewing a, is there a way to see 'all classes that have extended this class A'... therefore showing 'Class B'.
EDIT:
Thanks for that. There is an API I am reading at the minute where I was certain there had to be subclasses... turns out it doesn't! Interesting.
Javadoc should automatically generate the "Direct known subclasses" section, which in this case would list class B.
You shouldn't need to do anything to make this show up, so if you're not, there's a possibility it's a bug in the javadoc generator (however, unless you've presented a simplified version here, I'd be surprised if this trivial case triggers it).
Outside of your IDE javadocs in browser have a header "Direct Known Subclasses:" like the one in the javadoc for ArrayList. In IntelliJ IDEA all implementations/extensions of currently viewed interface/class can be seen if you press + B.
Related
While processing an annotation, I want to get all the subclass/subtypes of an element.
The element will be a Movie so I would like to get Elements or TypeMirrors of TerrorMovie and ComedyMovie.
interface Movie {}
class TerrorMovie implements Movie {}
class ComedyMovie implements Movie {}
Getting the superType is easy as I can use the Types.directSupertypes() but how can I get the subtypes?
Thanks
You can't. You can work around it though. You need to understand the significant limitations fundamental to the question 'We are compiling class X; can I get a list of all subtypes of this class?', because otherwise you're going to shoot yourself in the foot. Then I'll get to the workarounds.
The issue is, a superclass is fine. After all, this:
class Bob extends Alice {}
is not even going to compile if Alice is not available either as source file or as compiled class file when the compiler attempts to compile Bob. Therefore, asking the annotation processing (AP) tools to give you a TypeMirror object representing Alice is fine. It'll be there.
However, given that somewhere else in the codebase, class Carol extends Bob {} exists, is irrelevant, and if neither that source file nor that class file is around, Bob.java still compiles just fine. That's why the AP tools API doesn't give you a .getSubtypes() method. Because the docs would have to say something like this:
/**
* Finds all subtypes that are mirrorable in the current compilation context
* <b>but this does not do what you think it does and will miss a ton of classes,
* please read a page worth of caveats or prepare to shoot your foot off</b>:
*
* <ul><li>loooong list of caveats here</li></ul>
*/
Whereas the same list of caveats aren't necessary for getSupertypes(), because the cases where supertypes cannot be found are rare, are going to stop compilation anyway, and can thus don't apply (APs don't run when compilation errors occur, or if they do, it's not likely to be important that they can't do the job right).
You have 2 crucial issues:
In any case, 'search the universe is impossible'
I can write a class that extends AbstractList. I can do it right now: class ReiniersList extends AbstractList<String> {}. That was easy. When Team OpenJDK compiles AbstractList.java, of course ReiniersList cannot be returned when they run an AP that calls a hypothetical .getSubtypes().
So, you need to figure out what kind of subtype do you want. "Anywhere in this package?" "Anywhere in the source and classpath?" That last one is impossible - the classpath abstract simply does not support a 'list' directive. And yet that's probably what you intended to do here. The best option, in the sense that it really is the only thing that the AP API can meaningfully give you, is 'please give me all subclasses of this class that are part of the current compilation run, and only in source file form'. In other words, if you run javac *.java in a package and this hits AbstractFoo.java, FooImpl1.java, and FooImpl2.java, then asking 'getSubtypes()of the TypeMirror representingAbstractFoo, you would be able to get FooImpl1andFooImpl2` typemirrors. That's possible.
The problem is, programming teams split projects, and other code that doesn't even exist yet could extend AbstractFoo 5 years from now and you can't get those in the list. You're going to have to make crystal clear what you actually 'mean' when you ask for subtypes, and then check if that definition is something that the AP tools can even provide for you.
Inners
method-local classes can extend a type but aren't part of the type mirror infrastructure. They cannot have an impact on type resolution. This is a rarely used java feature, perhaps you don't know what I'm talking about. It's this:
class Example {
void foo() {
class MethodLocalClass extends AbstractList<String> {}
}
}
is legal java, actually. Yes, I stuck a class def in the middle of a method declaration. Outside of the method decl this class is utterly invisible. You can't write Example.MethodLocalClass anywhere, except inside foo(). Because of this, this class does not exist at annotation processing time, effectively. You can't ask for it. It has no accessible fully qualified name. Nevertheless, it could be a subclass. Point is, getSubtypes() cannot return it, ever. If that is a problem, then you can't do this at all. Hopefully, you're okay with this.
Incremental compilation
That problem of 'search the universe is impossible' takes on an acute role in making what you want completely impossible, at least as far as the AP tools are concerned, when you factor in that most compilation is done incrementally: Only the source files that need recompilation (because they were modified) are recompiled. That means if you have AbstractFoo, FooImpl1 and FooImpl2 all in the same package, and you edit AbstractFoo and FooImpl1, but don't touch FooImpl2, and then save and recompile, your compiler infra (be it an IDE, or maven, or gradle, or some other build tool) is rather likely to compile only AbstractFoo and FooImpl2 which means it is not possible for the infra to give you FooImpl1.
Even though FooImpl1 is in the same project (in the same package, even!). And there is no way to ask: It's simply not in the 'source set' of the compiler, and the classpath does not support a 'list' directive (where FooImpl2.class lives - after all, that's why it's not part of the source set, it already exists and does not need to be recreated).
Solutions
The main solution is to do a lot of bookkeeping yourself:
First, understand that you cannot ever get a list of stuff that lives outside your project. Only files that, on a complete clean recompilation run, would be touched, can be found. If it's in a different project built by the same team, you can find it, but stuff others write, or stuff that will be written in the future, you can never find that. Ensure you don't need these, or we're done.
Bookkeep every class you touch. Make a text file and write this (using the Filer, you can write non-java files too) into the output directory, listing all types you 'touched'. Then, on init, read this file, and for each class in it, ask the type tools for this type. This 'solves' the "classpaths cannot list" problem: Now you're not 'list all types and find me every type that extends X', now you are simply asking: "Please give me a TypeMirror representing class X, get it from the source path or the class path, and tell me what types that type extends". Crucially, that second thing is something the AP infra can do. You then do a quick 'cache clear' - whatever classes do not exist anywhere, you now know - I guess someone deleted that file. For everything that does exist, then that is one of the subtypes, though they might not be part of this compilation 'source set'.
You read the file during init, then you go through the rounds, extending this Set<String> (representing fully qualified types that are subtypes, automatically getting rid of duplicate names), and then on the last round (when roundEnv.isLastRound() is true), you check each type if it still exists and is a subtype of what you intended to be. And now you have your list of subtypes. Write this pruned list back for future runs, and do whatever you want to do with 'you now have a list of type names that extend the type you are interested in'.
I'm not aware of any libraries that can help you with this. It's not too hard to write it yourself.
This principle of 'write a file that contains, per line, the fully qualified type of some relevant type' smacks a lot of the SPI system, but crucially this one runs during compilation whereas SPI is designed as a runtime discovery system.
There are a large number of classes in this codebase which use a specific interface. However, picking a few at random, I've been unable to find one which is actually called anywhere; as such, I don't have a great idea of how to use it.
Is there a way in Eclipse to find every instance of any class which implements this interface?
In other words, suppose there exists an interface Interface, and classes ClassA, ClassB, ClassC, ..., ClassX, which all implement it. I want to see every point in the code where something like `ClassX obj = new ClassX(). Most of the classes I'm finding that implement this interface don't have any point where they're actually used; I assume they're for future use.
Open the interface class, hold Control and move your mouse to interface's name, select open implementation. That's the simplest and easiest way to do.
Yes, highlight the interface name and hit F4 or right click -> Open type hierarchy.
Update after OP's edit:
If you are using a framework that uses dependency injection like spring probably you don't find any reference because some of the implementations are defined in a xml file.
Also consider if some implementations are created and invoked via reflection.
Some classes might be loaded during runtime e.g. using reflection. To catch-them-all you can set a method entry breakpoint on the interface method. This is explained in this answer. That way all calls to implementation methods will suspend the JVM regardless of what is the object type.
Do note that unlike the line breakpoints the method breakpoints will really slow down the performance of the JVM.
I have been perusing the open source code of JMapViewer. If anyone else wishes to look at it, check the SVN.
In a nutshell, the main class is JMapViewer, which is an extension of a JPanel. There is another very important class called DefaultMapController which acts as a MouseListener for the main class.
The first weird thing I noticed is that the viewer has no references to the controller. The JMapViewer constructor instantiates an anonymous instance of the DefaultMapController, like this:
public JMapViewer() {
// other stuff
new DefaultMapController(this);
}
This seems to me to be a poor design choice, since the controller has tons of methods (options, toggles, etc - example shown below), which now can not be accessed at all, so what good are they?
public void setMovementMouseButton(int movementMouseButton) {
// changes which mouse button is used to move the map
}
The controller does have a reference to the viewer as shown in the first snippet above, which is how it is able to exercise control.
However, then I thought of something even weirder! If this anonymous instance of the listener has no references, why is it allowed to even survive? Shouldn't the GC destroy it quickly? Or is GC smart enough to know that a listener class which references a live JComponent must also stay alive to work properly, even if it has no name for some strange reason?
So, two real questions:
why does GC not destroy object?
is this indeed a poor design choice, or is there some way I'm unaware of to access the controller from the class which instantiates the viewer?
I want to contribute to this open source library, and my first idea for a change is to change the JMapViewer class to have a field referencing its controller, and to change the constructor to assign the currently anonymous controller to this new field. But, I want to make sure I'm not ignorantly missing something. I have searched the entire codebase for the text DefaultMapController, and it only occurs in its own class definitions, and in the anonymous instantiations in the JMapViewer constructors.
EDIT:
It does indeed appear that there is a way to access the anonymous listeners, by using the java.awt.Component method getMouseListeners(). So technically in my application I could search this collection for instances of DefaultMapController, and use that to access the methods I need to use to change the controller options.
To play devil's advocate though, if I go with original idea and give the map a reference of its controller, now I have a sort of circular reference (map knows of controller and controller knows of map). Is this a bad idea?
The abstract parent, JMapController, holds a reference to the JMapViewer passed there by the DefaultMapController constructor:
public DefaultMapController(JMapViewer map) {
super(map);
}
Addendum: The map reference held by the controller is used to (selectively) add up to three controller references to the map's EventListenerList, discussed here. Any one of these would preclude GC. At least one salutary design benefit is that a concrete JMapController need only implement available interfaces.
As suggested in this MVC outline, it would be unusual to give the view a reference to the controller. In contrast, there's nothing wrong with letting the controller register as a listener to the view, as suggested here.
Note that only the no-argument JMapViewer constructor installs a DefaultMapController. You can use the alternate constructor, as noted in comments at line 57-59 in revision 29113 of Demo.java. A complete example is examined here.
1) Everything you know is that, if and when the VM deems it to be appropriate, it will collect some or all of the dead objects. The GC is not required to do anything.
2) The best thing is to ask to the maintainer of the library. Anyway, as a general rule, I would not bother to change anything unless there's a good reason to, e.g. if it sensibly improves readability, and would rather focus myself on real problems.
3) Not sure if that's the case, but, when you serialize a JComponent, you also serialize all of its fields. And you do not want to serialize a lot of unused stuff.
I'm currently using a Java framework with quite long class hierarchies. When crawling through a class's code path, I have to jump back and forth between the different classes within this hierarchy.
I'm looking for a tool or Eclipse View that provides a "synthetic merge" of a class's full implementation with ALL its most concrete methods. Is there something like this?
For instance, I have to work with this class implementation hierarchy:
InternalResourceViewResolver extends UrlBasedViewResolver extends AbstractCachingViewResolver.
Now when reading code within InternalResourceViewResolver, there are calls to methods of its supertypes. Browsing back and forth (using "Open Declaration" (F3) and the back button (Alt+Left) ) can get confusing: I start loosing focus and happen to mistakenly read a superclass's method implementation that actually gets overridden by the subclass I investigate.
If you hold the SHIFT key when you hover over a method or class name, it will show you the source code it inline! You don't have to jump to it.
When I see a super.doFoo() method, I shift-hover to see what it does! If it's interesting, I CTRL+Click or either F3 to jump to the source.
One thing that might help is a (relatively little known) "bookmark" feature that's available in Eclipse:
http://www.luisdelarosa.com/2005/02/16/eclipse-tip-use-bookmarks-to-track-important-places-in-your-code/
I know one can use '<alt><shift>J' to create tags for a single code element (class method for example).
But is there a way to automatically create these tags for every class in the entire project? Or even just at package or class level?
Have you looked at JAutodoc?
Not that I know of.
What would that be good for anyway? Autogenerated Javadoc comments are worse than useless; I'd rather not have them cluttering up my code, and Javadoc will provide as much information even with no comment present.
Automatic generated JavaDoc is a pain, because other people never now what the method should do and yourself will also not know it, when you look at the class one year later.
Please comment your methods by yourself or do not comment the method.
My company is using checkstyle to force the employers to add javadoc. Some employers hate it to comment their methods and just type sensless comments. It would be better that their is no comment than a useless.
With checkstyle you can find all undocumented methods, to document them in a well format.
What will help you to document an init method like
"init has to be called before any
other method and initializes the class
ActionDummy"
it is better to tell what exactly is done
Inizializes the default state of the
action provider. Some state variables can be
overriden by the listener when ....