Abstract: The JavaDoc tool can do more than just generate HTML documentation for our Java classes. We can also write our own "Doclets" to scan the source code in our project. In this newsletter we look at how we can (ab)use JavaDoc to look for classes with non-private fields.
Welcome to the 35th issue of The Java(tm) Specialists' Newsletter. Two newsletters ago I mentioned checked exceptions and that perhaps they were a mistake. I also mentioned that I got that idea from someone else, that someone actually having been Bruce Eckel. Bruce and I had some very lively and interesting discussions regarding checked exceptions prior to my newsletter, and some of the ideas were gleaned from those discussions. Bruce has put up a website on www.mindview.net/Etc/Discussions/CheckedExceptions, where you can now voice your opinion on that matter. Please join us and tell us what you think. On that forum I've posted a way in which you can switch off exception checking in the compiler *evil grin*.
I'm always grateful for good publicity for my newsletter, so thanks also to Chris Preimesberger of DevX for publishing the exceptions newsletter on their website (www.java-zone.com/free/articles/Kabutz03/Kabutz03-1.asp). Please remember to forward this newsletter to your friends and collegues.
1618 members are currently subscribed from 55 countries
javaspecialists.teachable.com: Please visit our new self-study course catalog to see how you can upskill your Java knowledge.
What makes code bad? Is it the result of mistakes in logic? That makes the code incorrect, but not bad. Bad is one of those fuzzy attributes that are hard to define. It makes your stomach turn, fills you with dread, confiscates your mind ...
What makes coders bad? Lack of experience? Sloppiness? Bad training at universities by lecturers who themselves are bad coders? I once made the mistake of suggesting that the company, at which I was working at the time, give a Dutch student an opportunity to get some real-life experience. The code was indescribably bad! All the data members used package access, every class was in the same package, the whole program was one long nested if-else statement.
One of the things that makes this hobby of newsletter writing satisfying is the feedback I get from readers. Some time in June this year I was busy working for a German company (Infor AG) developing a subcomponent based on Doclets (I will write more about that in another newsletter).
At the same time, one of my readers at CitiCorp in India sent me an email, asking me for help. She was working in the quality control department of the coding group and was looking for some easy way of enforcing company policies with regard to coding. Since I was working with Doclets anyway, we had some interesting discussions on how you could use Doclets to solve her problems.
On another continent, Bruce Eckel was busy writing solutions for the exercises in his book. Naturally, he also wanted to make sure that his exercises did not contain "bad code" by mistake, so this newsletter is the result of a cooperation between Java users across three continents :-)
Let's get back to what makes code "bad". I believe that code is "bad" when it is difficult to maintain. In the refactoring literature, they say the code "smells". You might have code which is 100% correct, and yet still is "bad". How is that possible? If you don't believe me, wait until you have to change that code ...
There are certain "things" that we do which make code bad. Inappropriate variable names, making data members non-private, not having comments describing what each parameter is supposed to do, etc. But if you have a Java project with 2'000'000 lines of code, how do you find the code that is "bad"? Fortunately there is a solution that is not going to cost you the license fees of a Together/J, provided by Sun Microsystems in the form of Doclets.
The documentation for Doclets is in an obscure place. Go to your
JDK documention, then to Tool Docs, click on Basic
Tools, and under javadoc you'll see Javadoc 1.3 Home Page.
All you have to do is write a method public static boolean start(RootDoc root)
that is the starting point for the doclet engine. Let's have a
look at some code that will find any non-private data members in
your classes:
import com.sun.javadoc.*; /** This class is used as a Doclet and will find any non-private data members in your classes. */ public class CodeChecker { /** This is the entry point for the doclet engine into your class. */ public static boolean start(RootDoc root) { System.out.println("Non-private data members:"); checkClasses(root.classes()); return true; } /** We will call the checkClasses() method recursively so that we can also check the inner classes (for what it's worth). */ private static void checkClasses(ClassDoc[] cds) { for (int i=0; i<cds.length; i++) { checkDataMembersArePrivate(cds[i]); } } /** This method prints out any data members that are not private together with their access. If the field is package access we print out no modifiers. */ private static void checkDataMembersArePrivate(ClassDoc cd) { System.out.println(cd.modifiers() + " " + cd.qualifiedName() + ":"); FieldDoc[] fields = cd.fields(); for (int i=0; i<fields.length; i++) { if (!fields[i].isPrivate()) { System.out.print("\t"); if (!fields[i].isPackagePrivate()) System.out.print(fields[i].modifiers() + " "); System.out.println(fields[i].type() + " " + fields[i].name()); } } checkClasses(cd.innerClasses()); } }
The code above is dead-easy, but how do you use it? First you
have to compile it, and you will need to include tools.jar in
your classpath, e.g. javac -classpath .;c:\jdk1.3\lib\tools.jar *.java
Note that the tools.jar file is not part of the runtime
distributable, so if you want to use these features on your client
machines, they will have to install the JDK, instead of just the
JRE. Before we look at how we run Doclets, let's look at an
example that we can use to test on:
public class Test { String packageAccess; private String privateAccess; public String publicAccess; protected String protectedAccess; public static final String NAME = "Hello"; }
We compile Test.java as well and now we can see how the Doclet is run:
javadoc -private -doclet CodeChecker Test.java
The resultant output is:
Loading source file Test.java... Constructing Javadoc information... Non-private data members: public Test: java.lang.String packageAccess public java.lang.String publicAccess protected java.lang.String protectedAccess public static final java.lang.String NAME
You would have to of course match up your program with your
company policy in order for this to be successful. For example,
in your company you would probably say that it's OK for a data
member to be public
as long as it also
was static
and final
.
More importantly than writing such a program is running it
regularly, and suitably punishing those programmers found guilty
of violating "the code" (in those countries that allow it, perhaps
a public
beheading would be appropriate?
- oh no, rather a private
one; otherwise
they'd be violating their own rules.)
Would you use Doclets to do things to classes "in real time"? I would suggest you wait for the newsletter on how I tamed Doclets before you try that ;-)
My apologies again for not getting this newsletter out as regularly as I would like to. My excuse is rather lame - I'm busy writing a program for a company, and I love programming so much that everything else takes second place. The coding was also quite a rushed job, which is why I'm busy on a Saturday afternoon writing a newsletter when all my colleagues are on the beach ;-)
On the 30th of November we are celebrating our 1st anniversary as The Java(tm) Specialists' Newsletter. I would really appreciate it is you could make an extra effort to spread the word before that, so we can see some good growth.
Kind regards, and until next time...
Heinz
We are always happy to receive comments from our readers. Feel free to send me a comment via email or discuss the newsletter in our JavaSpecialists Slack Channel (Get an invite here)
We deliver relevant courses, by top Java developers to produce more resourceful and efficient programmers within their organisations.