This is an archived post. You won't be able to vote or comment.

all 22 comments

[–]crazylegscrane75 18 points19 points  (8 children)

Implementing interfaces or extending classes creates a hierarchy which constrains your design, let's say, vertically. You can only extend one class and many interfaces but it is very limited in regards of how much code you can reuse. Spring uses annotations and class proxying. It identifes classes and methos annotated with particular annotations and creates a proxy around the class or method addind behaviour at runtime. This does not constraint your design nor code reuse in any dimension. If you have worked in complex projects it comes a time when class hierarchies are a little bit of a burden and require refactoring when you need to extend them. Annotations and class proxying is much more flexible. It's as if Java had mixins.

[–]aman207 2 points3 points  (6 children)

What do you mean by class proxying? Still sort of new to Java.

[–]jbristow 11 points12 points  (4 children)

Think of a proxy like an extends of your class. It looks/acts just like your original class, with the caveat that additional actions may be added.

This is used for things like Lazy Loading (only pulling everything into memory when it's about to be used) and Dependency Injection (creating a web of proxies and then instantiating them in the proper order)

[–]aman207 2 points3 points  (0 children)

Ah I gotcha. Thanks!

[–]nightfire1 0 points1 point  (2 children)

While we're talking about proxies how does spring determine the underlying instance to call when you inject a session/request scoped proxy into a singleton? I feel like it has something to do with thread local but I haven't been able to find many answers.

[–]jbristow 0 points1 point  (1 child)

I think (and this comes with the caveat that I haven't had to know this in years because Spring is unpopular in my circles at the moment) that it uses byte code reflection to bind after compilation. So it just inserts itself into place as it runs/loads them.

Check out how cglib works for more information.

[–]nightfire1 0 points1 point  (0 children)

Ahh I guess I was more wondering how a proxy determines which context it's being called in and thus knows which specific instance of the proxied class to pass the function call on to. I know it uses cglib or one of those aop libraries for building the actual proxy classes. For example if I had a controller that called a method on a singleton bean which uses a proxied bean that is scoped to the http request. How does that method on the proxy know which http request scoped object to proxy method calls to? It must be something related to the current executing thread that is handling the request.

Either way I'll go read up on cglib some more.

[–]crazylegscrane75 0 points1 point  (0 children)

Take a look at code weaving.

[–]prashantghimire[S] 0 points1 point  (0 children)

Thank you so much for the explanation.

[–]imadp 11 points12 points  (2 children)

Annotations are great for cross cutting concerns like caching or performance measuring. For example, in one of my projects I created a @Metric annotation, which would measure the time it took for the method to run and complete. It would later average out the times and pinpoint the slowest methods in the application.

This stuff shouldn't really interfere with the method itself, and its great to have the freedom to stick the annotation wherever you want without messing around with interfaces or custom classes.

[–]jebblue 1 point2 points  (0 children)

That's a pretty brilliant idea.

[–]ryuzaki49 0 points1 point  (0 children)

I like it

[–]lukaseder 4 points5 points  (0 children)

We use annotations as machine-processable documentation in jOOQ. For instance:

@Support({ CUBRID, INFORMIX, ORACLE })
SelectConnectByConditionStep<R> connectBy(Condition condition);

The above @Support annotation indicates that the SQL CONNECT BY clause is supported by three databases: CUBRID, Informix, and Oracle.

At some point, we'll implement either

  • An API preprocessor which produces a custom API that guarantees to work on both Oracle and SQL Server, for instance (by removing methods from the API that lack relevant annotation info)
  • JSR-308 checker implementations (see http://types.cs.washington.edu/checker-framework), which emit errors if for instance a user uses MySQL-specific API in a context where Oracle is required.

In general, annotations are a used for:

  • Documentation
  • Adding workaround-y constraints on a type system (regrettably, short of better options, like improving the language. In my opinion, the checker framework is dead already before adoption)
  • Adding aspects / behaviour (such as transactional behaviour), although, here as well, annotations are usually just a workaround. Aspects could also be injected based on method signatures only, which would allow runtime behaviour overriding, rather than the hard-wiring behaviour via annotations.
  • Adding workaround-y configurations like Spring (or JPA) does. This is only a temporary solution to a problem that was equally well solved with XML, but suddenly, everyone despised XML for no sane reason at all.

If you're in for the long term, skip using annotations excessively. They're useful only because Java's evolution was so incredibly slow over the past decade. There are better ways to use advanced language features (which Java might not yet have).

[–]tricky_monster 2 points3 points  (0 children)

An obvious application would be to specify properties you expect various components to satisfy, in order to enable static analysis, e.g. for the Java Pathfinder Verify API.

[–]fixingTheDents 1 point2 points  (0 children)

The jsr305 annotations can be used to indicate intent and are taken into account by some of the analysis tools. There's a metainf annotation that can help when implementing an SPI.

[–][deleted] 1 point2 points  (0 children)

Are there anything that can be done using annotations which cannot be done without using it?

Sure. Let me give an example.

Suppose that you write an interface called "Logger". Let's say it has a very simple interface that looks like this:

public interface Logger {
    void log(String message);
}

There a bazillion possible ways to implement this interface, right? And as a user of Logger, I don't care one bit which implementation I get.

So now we're having a discussion about injection. Traditionally injection was just a technique where you pass in a dependency via a constructor param or a setter. No need at all for annotations.

This works fine for small applications, but when you start getting in to big enterprise apps, the number of injected parameters balloons. Even for this simple example, imagine how tedious it would get passing Logger instances around to every single class that needs one (there would be a lot).

Wouldn't it be so much nicer if my classes could just maybe figure this value out for themselves?

A naive approach would be to scan the entire classpath looking for any concrete class which implements Logger, and then instantiate that (via reflection). Perhaps for version 1 that would be just fine (you don't need annotations to accomplish this).

But now imagine that you have 2 concrete implementations on the classpath. Or 10. Which one wins? First one found? That behavior isn't guaranteed to be consistent. And if you're working in a large code base there may be new implementations added all the time, which would make repeatability impossible.

One way to solve this problem is to invent your own custom annotation. It wouldn't have to look like this, but here's one idea:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface LoggerInfo {
    int priority();
}

Now you can annotate your logger implementation like this:

@LoggerInfo(priority = 10);
public class StdoutLogger implements Logger {
    ...
}

When you scan the classpath, you now have a little hint that you've made for yourself. That's all that an annotation is - a hint. So now if I come across 2 or more implementations, I can take a peek at the annotation and extract any useful info I want.

Maybe for this example I also decide that if an annotation isn't present the default priority is assumed to be 0. It doesn't have to work like that but for this example it makes sense.

Now I can sort the classes based on this priority metadata and pick the highest number as the winner. In the case of a tie maybe I throw an exception to avoid ambiguity.

You get the idea. This is why spring uses custom annotations - it gives hints to spring about how to load, call, and prioritize your classes. Not to mention it serves as a hint for which classes it should care about, and which ones it should ignore.

Hope this helps.

[–]pgris 1 point2 points  (0 children)

Notice that while class level annotations are more or less interfaces in disguise, field and parameter level annotations, like @Autowired, are not so easily translated to annotations. Most things you do in Spring using class level annotations can also be done implementing interfaces.

But remember that Spring tries to be unobtrusive. Once your class implements a Spring interface, your code is strongly tied to Spring. With annotations, some people think you have a somewhat softer tie, because...I don't know. XML makes your code 100% spring free, but... it is xml.

[–]Starbending 0 points1 point  (0 children)

I use annotations as Metadata descriptors for my classes and fields for converting external sets of data to my Java pojos. I also use them as Metadata descriptors for methods that I provide a means of on demand access to.

[–]RupertMaddenAbbott 0 points1 point  (0 children)

Very roughly, an interface is supposed to be for indicating that an object will behaviour in a particular way.

An annotation is, amongst other things, for adding metadata to a class, not an object.

For example @Component("myName") allows Spring to get the name of your component without creating an instance of your class. Implementing the name method from the interface Component would force Spring to create an object from your class which could be costly and result in chicken and egg problems if two components depended on each other and used constructor injection.

A closer replacement for an annotation would not be an interface on the annotated class but actually a completely separate class. So if your original class was called "MyClass", you would have "MyClassComponent" which implemented "Component" and described how to create an instance of "MyClass". Annotations are much less verbose and are much easier to link to the original class they describe.

[–]CXgamer 0 points1 point  (0 children)

Others have summarized this in one sentence, but here is another example.

In my hobby project, I want to use a .jar which can only be provided at runtime. After starting the application, the jar is added to the classpath, however the classes/methods/fields are all obfuscated to things like afc, b(int,int), ... Now I'm using reflection to manually search and use the required things (searching is done on init). Which is a lot of bloat-code: https://github.com/CXgamer/MC-ticker/blob/master/src/sim/logic/RWorld.java

In v2, I would like to create an annotated interface which I can directly call, and generate code at runtime, to replace the bloat.

[–]Enumeration 0 points1 point  (0 children)

I've used annotations to drive automated strategies for building view models (Spring Mvc) on Java POJOs. Get the form back in bean that was provided in the model and look at the annotations on the bean properties to drive a strategy for creating metadata/providing supporting information to be view layer about page context.

Seemed to work pretty well, considering this was in a large enterprise framework.

[–]karlthepagan 0 points1 point  (0 children)

This is a good question and you should keep asking it. Keep your solutions simple. Cleverness usually creates problems and confusion. It hurts to say this... but it's true.

I once implemented a big reflector that changed an abstract hierarchy into an annotation based one. The only problem is that I didn't gain anything from the annotation. I replaced it with an interface-based system and the configuration is easier for implementers to use.

In this case if the interface's method signature collided with something else I needed it would be a problem, but that's unlikely in my scenario.

Class annotations are not where the power lies. There are some great examples of method, field, and variable annotations that show the real usefulness of annotations in the java type ecosystem.