Wednesday, November 13, 2013

deadcode4j v1.4 released

deadcode4j v1.4 is out! It is available via Maven central, so it is conveniently available for your Maven project.

What's new?

Version 1.4 was all about customization, so that you can unleash the power of deadcode4j without waiting for the nth feature to be added:

  • Additionally to the annotations that can be configured, you can now define interfaces which, if implemented by a class, mark that code as being in use
  • With annotations and interfaces, there's only one thing missing: superclasses - and they can be configured as well, thus marking subclasses as being in use
  • As deadcode4j processes the whole reactor, there may be some example/testing modules which should not be considered - so now you can specify if a module shouldn't be part of the analysis

This should help you eliminate a good portion of the false positives being found by deadcode4j right now, helping you set up a configuration which recognizes dead code.
Nevertheless, v1.4 brings some more analysis features:

  • Classes being listed in web.xml files as contextClass or contextInitializerClasses parameter for Spring's ContextLoader or FrameworkServlet are recognized as live code
  • Hibernate Annotations processing:
    • Classes referenced by the strategy parameter of a @GenericGenerator annotation are recognized as live code
    • Classes referenced by the type parameter of a @Type annotation are recognized as live code
    • Classes annotated with @TypeDef being referenced by a @Type annotation are recognized as live code
  • package-info classes annotated with JAXB's @XmlSchema annotation are recognized as live code
  • Classes being annotated with any of a bunch of JSF annotations are recognized as live code
  • *Descriptor classes being generated by Castor are recognized as live code

How to use

It's so simple: go to the console, navigate to your Maven project, type
  mvn de.is24.mavenplugins:deadcode4j-maven-plugin:find ‑Dmaven.test.skip=true
and see what it finds.

Hop on over to GitHub to learn more, browse the code, or contribute.

Looking for reference projects & users

Currently I'm using the big legacy application of my employer as a reference project. But I'm slowly running out of false positives, so my feature list is shrinking. That's why I'd love to analyze some more projects to get more feedback. So, if you know of an (open source) candidate I can analyze or if you are using deadcode4j for yourself and want something added or you have some nice ideas, please comment!

Here you can read how it all started.

Monday, October 28, 2013

deadcode4j v1.3 released

I recently released deadcode4j v1.3. It is available via Maven central, so it is conveniently available for your Maven project.

What's new?

Two now analysis modes were added:

  • Classes annotated with Spring annotations like @Component or @Repository (amongst others) are considered to be live code
  • Classes annotated with JEE annotations like @ManagedBean, @Named or @StaticMetamodel are considered to be live code

Additionally, you can specify which annotations mark classes as live code, and configure a custom XML analysis such that an XML element's text content or an attribute is considered to be a class in use. This should help enormously to reduce the number of false positives being recognized.

How to use

It's so simple: go to the console, navigate to your Maven project, type
  mvn de.is24.mavenplugins:deadcode4j-maven-plugin:find -Dmaven.test.skip=true
and see what it finds.

Hop on over to GitHub to learn more, browse the code, or contribute.

Looking for reference projects & users

Currently I'm using the big legacy application of my employer as a reference project. This is ok, as there are still some false positives, providing me with a feature list for a couple of more releases. However, I'd love to analyze some more projects to get even more feedback. So, if you know of an (open source) candidate I can analyze or if you are using deadcode4j for yourself and want something added or you have some nice ideas, please comment!

Sunday, October 13, 2013

deadcode4j v1.2.0 released

Today, I released deadcode4j v1.2.0! It is available via Maven central, so it is conveniently available for your Maven project.

What's new?

Two now analysis modes were added:
  • web.xml files are parsed and each listed servlet, filter & listener is considered to be live code
  • *.tld files are parsed - thus tags, tag extra info classes, listeners, tag library validators & EL functions are considered to be live code

On top of that, if a project uses war packaging the webapp directory is analyzed instead of the project's output directory to catch those web.xml and .tld files. Therefore, the package phase is executed on the fly.
Finally, the plugin now recognizes reactor projects, meaning each listed module will be analyzed by deadcode4j, providing a holistic view over a complex project.

How to use

It's so simple: go to the console, navigate to your Maven project, type
  mvn de.is24.mavenplugins:deadcode4j-maven-plugin:find -Dmaven.test.skip=true
and see what it finds.

Hop on over to GitHub to learn more, browse the code, or contribute.

Looking for reference projects & users

Currently I'm using the big legacy application of my employer as a reference project. This is fine, as I still have a sizable amount of false positives, providing me with a feature list for a couple of more releases. However, I'd love to analyze some more projects to get even more feedback. So, if you know of an (open source) candidate I can analyze or if you are using deadcode4j for yourself and want something added or you have some nice ideas, please comment!

Wednesday, October 9, 2013

Introducing deadcode4j

Motivation

Dead code is everywhere. I guess that most sizable software that underwent at least one major rewrite or is taken care of by agile teams which do minor rewrites every week or so, caries with it at least one dead class; not to mention the one or other dead method. When dealing with legacy code especially - consisting of many modules, older than the programmer with most seniority, with little to no tests - the share of the code base being dead can easily grow up to a double-digit percentage. So, when dealing with such code, you may end up adapting classes when you needn't bother, which you shouldn't try to understand - but just delete them and grin.
And in times of continuous integration, this causes unnecessary energy consumption and time spent in build queues that could be empty, waiting for other stuff to do than compiling and testing code that served its purpose a long time ago.

So, code analysis is a great thing. If your home is the Java world, you should know (and sometimes even make use of) such great analysis tools like FindBugs, PMD, or Checkstyle - to name the probably most prominent. This should at least help you get rid of some dead variables and methods. But those tools are usually only capable of validating local usage, restraining them to find unused private methods. And if you're dealing with code from a time where using the private modifier wasn't en vogue - poor you. And talk about whole classes? Just forget about it.
I don't know of any reliable, automatable tool helping to identify dead classes. Sure, IDEs tend to claim that certain classes are not used. But if you don't load all modules - that information may or may not be correct. And legacy code with nearly hundreds of modules? Try putting that in your IDE...

The quest for the dead

So, guess what: I actually had (and sometimes still have) to deal with such supposedly dead code. One approach I took to identify such code was setting up a build in our TeamCity instance executing IntelliJ's inspections. Well, there seems to be a limit for everything. I managed to get one finished build out of hundreds of executions. After upgrading to TeamCity 7, builds were finally running. It still took hours to perform the simplest checks (and a bunch of others I just couldn't turn off, as this is a not-that-well-documented feature) and the report came up with many false positives, even such you wouldn't expect: classes being referenced in several Spring XML files, which are perfectly recognized in IntelliJ Idea. Again: there seems to be a limit for everything.

I'm a peaceful mind, but sometimes you need to use brute force. So I wrote a bash script that looped through all classes, removed one, executed a remote run against our continuous integration system, noted the result, reverted the change and went on. Every other day I looked at the results, did a manual double-check (I failed only once), actually removed the dead code, and started the script again.
Even though I did this for only one of our 50+ modules - the one that was set up years ago to contain all the "business logic", having accumulated 2.8k classes over the years - it took me (or, mainly, the script) months to finally run dry (there were whole chains of dead code and the script only recognized one class after the other).  Me & my script managed to eliminate more than 15% of the code base. And I moved another 10% of the code to modules that really needed that classes. Man, I was pumped. And I thought: you're not the only one dealing with legacy code!
But when I decided to open source that thing, I realized that, over the course of months giving the script as little care as a full hour every other week, I could not. Apart from the fact that I don't know bash at all, the script was highly integrated to our build setup and required TeamCity to be executed. As my parental leave was at hand, I left my decision behind.

The missing piece

During that time, some of my co-workers took another approach during the Scout IT Day (our flavor of the FedEx or ShipIt Day) and created a Maven Plugin that chiefly used bytecode analysis to find out if a class was still in usage or not. And that's the starting point for deadcode4j.
deadcode4j is a Maven plugin that aims at finding dead code. It does so using bytecode analysis to find dependencies between code and additionally considers Spring XML files to determine if a class is still in use or not. And this is just the beginning: considering the web.xml, .tld files, @nnotations, and more is in the works.

And how can you use it? Simple: go to the console, navigate to your Maven project, type
  mvn de.is24.mavenplugins:deadcode4j-maven-plugin:find -Dmaven.test.skip=true
and see what it finds.
Hop on over to GitHub to learn more, browse the code, or contribute.
Watch out for announcements, new releases and ideas at sebastiankirsch.blogspot.com

Monday, February 18, 2013

GWT SuggestBox backed by POJOs

The other day I found an occasion to make a more sophisticated use of GWT's SuggestBox. Not only did I intend to use the "suggestion feature" based on a POJO's attribute, I also wanted to
  • fill more widgets with other attribute values of the POJO the suggestion was based on
  • present the data of the other attributes by showing them to the user beforehand; ideally as part of the suggestion itself
So, the user should see something like this
and after selection, values should be inserted like that
Although the basic idea of doing so was thought of by Google's engineers, there is no clear path given to ultimately get it done. I found a working example of how to achieve something similar over at the PermGen error blog. Kudos to the author over there - he certainly got me kickstarted. However, I found it awkward to manage the text matching "myself", especially as I liked the feature set of the MultiWordSuggestOracle (and wanted to offer the user the possibility to match the brand also); so I looked for a way to extend the latter.

Define our own Suggestion

We start easy by following the recommendation to implement our own Suggestion class:
public class ArticleSuggestion extends MultiWordSuggestion {
 private final Article article;

 public ArticleSuggestion(Article article, String displayString) {
  super(article.getName(), displayString);
  this.article = article;
 }

 public Article getArticle() {
  return this.article;
 }
}

Extending MultiWordSuggestOracle

This one's a bit tricky. Unfortunately, there are no hooks or plugin-points in that class with which to easily provide your own logic. Also, basically all of the text matching (the reason that made me want to extend it) is defined in private methods. So I ended up with a somewhat blunt approach - which obviously works for me, and I assume works for most scenarios as well.
public class ArticleSuggestOracle extends MultiWordSuggestOracle {
 private final Map suggestionMap = new HashMap();

 public void add(Article article) {
  String suggestion = article.toSuggestion();
  this.suggestionMap.put(suggestion, article);
  super.add(suggestion);
 }

 public void requestSuggestions(Request request, final Callback callback) {
  super.requestSuggestions(request, new Callback() {
   @Override
   public void onSuggestionsReady(Request request, Response response) {
    callback.onSuggestionsReady(request, modifyResponse(response));
   }

  });
 }

 private Response modifyResponse(Response response) {
  ArrayList articleSuggestions = new ArrayList();
  for (Suggestion originalSuggestion : response.getSuggestions()) {
   MultiWordSuggestion suggestion = (MultiWordSuggestion) originalSuggestion;
   Article article = this.suggestionMap.get(suggestion.getReplacementString());
   articleSuggestions.add(new ArticleSuggestion(article, suggestion.getDisplayString()));
  }
  response.setSuggestions(articleSuggestions);
  return response;
 }
}

Reacting on a selected suggestion

Now, set up a SuggestBox using the ArticleSuggestOracle, and assign a SelectionHandler just like that:
articleSuggestBox.addSelectionHandler(new SelectionHandler() {
 @Override
 public void onSelection(SelectionEvent event) {
  ArticleSuggestion suggestion = (ArticleSuggestion) event.getSelectedItem();
  Article suggestedArticle = suggestion.getArticle();
  handleSuggestedArticle(suggestedArticle);
 }
});
The power of the MultiWordSuggestOracle awaits you!