text: Annotations heavily. Take jcabi-aspects, for example. However, I'm not excited any more. Moreover, I believe that annotations are a big mistake in Java design.
  Long story short, there is one big problem with annotations—they encourage us to implement object functionality outside of an object, which is against the very principle of encapsulation. The object is not solid any more, since its behavior is not defined entirely by its own methods—some of its functionality stays elsewhere. Why is it bad? Let's see in a few examples.
  @Inject
  Say we annotate a property with
  @Inject:
  import javax.inject.Inject; public class Books { @Inject private final DB db; // some methods here, which use this.db }
  Then we have an injector that knows what to inject:
  Injector injector = Guice.createInjector( new AbstractModule() { @Override public void configure() { this.bind(DB.class).toInstance( new Postgres("jdbc:postgresql:5740/main") ); } } );
  Now we're making an instance of class
  Books via the container:
  Books books = injector.getInstance(Books.class);
  The class
  Books has no idea how and who will inject an instance of class
  DB into it. This will happen behind the scenes and outside of its control. The injection will do it. It may look convenient, but this attitude causes a lot of damage to the entire code base. The control is lost (not inverted, but lost!). The object is not in charge any more. It can't be responsible for what's happening to it.
  Instead, here is how this should be done:
  class Books { private final DB db; Books(final DB base) { this.db = base; } // some methods here, which use this.db }
  This article explains why Dependency Injection containers are a wrong idea in the first place: Dependency Injection Containers are Code Polluters. Annotations basically provoke us to make the containers and use them. We move functionality outside of our objects and put it into containers, or somewhere else. That's because we don't want to duplicate the same code over and over again, right? That's correct, duplication is bad, but tearing an object apart is even worse. Way worse. The same is true about ORM (JPA/Hibernate), where annotations are being actively used. Check this post, it explains what is wrong about ORM: ORM Is an Offensive Anti-Pattern. Annotations by themselves are not the key motivator, but they help us and encourage us by tearing objects apart and keeping parts in different places. They are containers, sessions, managers, controllers, etc.
  @XmlElement
  This is how JAXB works, when you want to convert your POJO to XML. First, you attach the
  @XmlElement annotation to the getter:
  import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class Book { private final String title; public Book(final String title) { this.title = title; } @XmlElement public String getTitle() { return this.title; } }
  Then, you create a marshaller and ask it to convert an instance of class
  Book into XML:
  final Book book = new Book("0132350882", "Clean Code"); final JAXBContext ctx = JAXBContext.newInstance(Book.class); final Marshaller marshaller = ctx.createMarshaller(); marshaller.marshal(book, System.out);
  Who is creating the XML? Not the
  book. Someone else, outside of the class
  Book. This is very wrong. Instead, this is how this should have been done. First, the class that has no idea about XML:
  class DefaultBook implements Book { private final String title; DefaultBook(final String title) { this.title = title; } @Override public String getTitle() { return this.title; } }
  Then, the decorator that prints it to the XML:
  class XmlBook implements Book{ private final Book origin; XmlBook(final Book book) { this.origin = book; } @Override public String getTitle() { return this.origin.getTitle(); } public String toXML() { return String.format( "<book><title>%s</title></book>", this.getTitle() ); } }
  Now, in order to print the book in XML we do the following:
  String xml = new XmlBook( new DefaultBook("Elegant Objects") ).toXML();
  The XML printing functionality is inside
  XmlBook. If you don't like the decorator idea, you can move the
  toXML() method to the
  DefaultBook class. It's not important. What is important is that the functionality always stays where it belongs—inside the object. Only the object knows how to print itself to the XML. Nobody else!
  @RetryOnFailure
  Here is an example (from my own library):
  import com.jcabi.aspects.RetryOnFailure; class Foo { @RetryOnFailure public String load(URL url) { return url.openConnection().getContent(); } }
  After compilation, we run a so called AOP weaver that technically turns our code into something like this:
  class Foo { public String load(URL url) { while (true) { try { return _Foo.load(url); } catch (Exception ex) { // ignore it } } } class _Foo { public String load(URL url) { return url.openConnection().getContent(); } } }
  I simplified the actual algorithm of retrying a method call on failure, but I'm sure you get the idea. AspectJ, the AOP engine, uses
  @RetryOnFailure annotation as a signal, informing us that the class has to be wrapped into another one. This is happening behind the scenes. We don't see that supplementary class, which implements the retrying algorithm. But the bytecode produced by the AspectJ weaver contains a modified version of class
  Foo.
  That is exactly what is wrong with this approach—we don't see and don't control the instantiation of that supplementary object. Object composition, which is the most important process in object design, is hidden somewhere behind the scenes. You may say that we don't need to see it since it's supplementary. I disagree. We must see how our objects are composed. We may not care about how they work, but we must see the entire composition process.
  A much better design would look like this (instead of annotations):
  Foo foo = new FooThatRetries(new Foo());
  And then, the implementation of
  FooThatRetries:
  class FooThatRetries implements Foo { private final Foo origin; FooThatRetries(Foo foo) { this.origin = foo; } public String load(URL url) { return new Retry().eval( new Retry.Algorithm<String>() { @Override public String eval() { return FooThatRetries.this.load(url); } } ); } }
  And now, the implementation of
  Retry:
  class Retry { public <T> T eval(Retry.Algorithm<T> algo) { while (true) { try { return algo.eval(); } catch (Exception ex) { // ignore it } } } interface Algorithm<T> { T eval(); } }
  Is the code longer? Yes. Is it cleaner? A lot more. I regret that I didn't understand it two years ago, when I started to work with jcabi-aspects.
  The bottom line is that annotations are bad. Don't use them. What should be used instead? Object composition.
  What could be worse than annotations? Configurations. For example, XML configurations. Spring XML configuration mechanisms is a perfect example of terrible design. I've said it many times before. Let me repeat it again—Spring Framework is one of the worst software products in the Java world. If you can stay away from it, you will do yourself a big favor.
  There should not be any "configurations" in OOP. We can't configure our objects if they are real objects. We can only instantiate them. And the best method of instantiation is operator
  new. This operator is the key instrument for an OOP developer. Taking it away from us and giving us "configuration mechanisms" is an unforgivable crime.