5

Suppose I have a class with an annotation, e.g.:

@MyConfig
class MyConfiguration {

    @MyParameter
    String parameter;
}

If I know an instance of this class exists (for instance, one was constructed in another thread) how can I get a reference to the instance elsewhere. I'm trying to find the instance by its @Annotation.

dimo414
  • 47,227
  • 18
  • 148
  • 244
barbara
  • 3,111
  • 6
  • 30
  • 58
  • 3
    You're saying an instance of an object might exist in memory, and you want to find it? Something like a (doesn't exist) `MyConfiguration obj = Runtime.getExistingInstanceOf(MyConfiguration.class);`? – dimo414 Aug 25 '14 at 21:29
  • 3
    Find it where? Somewhere in the heap? This's isn't really possible. – Boris the Spider Aug 25 '14 at 21:29
  • This may be your answer here: http://stackoverflow.com/questions/259140/scanning-java-annotations-at-runtime In particular pay attention to the comments of the accepted answer. I think this is the functionality you are looking for. – CarCzar Aug 25 '14 at 21:35
  • @CarCzar I now how to find a class by annotation. But the problem is if I have somewhere in heap (thnx to Boris) an object of class than I need to get somehow the access to it. – barbara Aug 25 '14 at 21:37
  • I don't want to registrate it in Context like in String. – barbara Aug 25 '14 at 21:38
  • 3
    @JimGarrison I don't think this question is the same as the duplicate - this question is trying to get pointers to instances of certain type (which happens to be an annotation). – dimo414 Aug 25 '14 at 21:38
  • Well, the question is extremely unclear as it stands. If the OP clarifies the objective I'll vote to reopen. – Jim Garrison Aug 25 '14 at 21:40
  • @dimo414 That's what I want. Exactly! – barbara Aug 25 '14 at 21:41
  • @JimGarrison I've edited the question slightly, barbara feel free to expand it further. – dimo414 Aug 25 '14 at 21:44
  • @Jim Garrison This question is not about scanning for annotations. I now how to scan. It's about finding an instance of class in the heap. I already have founded (by scanning for @) a class. – barbara Aug 25 '14 at 21:45
  • @barbara I've posted an answer going over some options, but I'll be able to give you better suggestions if I understand better what you're actually trying to do. If my answer isn't sufficient, please update your question with extra context - what are you broadly trying to do, why you think annotations are the right tool, etc. – dimo414 Aug 25 '14 at 22:11
  • What makes an instance different from another one just because it is annotated you still need to store an instance in a accessible place in order to retrieve it later. – Alfredo Osorio Aug 25 '14 at 22:17

1 Answers1

4

You cannot simply conjure up a reference to an object based on its type or annotations, nor should you really want to. The primary reason for this is garbage collection - the JVM cleans up memory for you as objects fall out of scope; if you could create new references dynamically, the garbage collector would not be able to safely clean anything up, and you'd rapidly run out of memory.

That said there's many ways you can build up functionality like you're describing pretty simply, so that you can look up an object by its type.

The easiest (and arguably best) way to do this is to simply register the instance you want, using a Map (consider Guava's ClassToInstanceMap). While you have to explicitly add to the map, that is actually going to be a lot cleaner for you in terms of code-compartmentalization. Even if you make the caching behavior a static method on the annotation, or something like that, separating construction from caching is a good practice to get into.

// somewhere accessible to both the constructing and accessing code, such as a
// public static field on the Annotation
Map<Class<? extends Annotation>,Object> annotationMap = new HashMap();

// wherever the instance is constructed
annotationMap.put(MyConfig.class, new MyConfiguration());

// wherever the instance is needed
MyConfiguration myConf = (MyConfiguration)annotationMap.get(MyConfig.class);

You've likely noticed that this holds Object values, because any class can theoretically be annotated, so we have to explicitly cast. This will work, assuming you enforce what types are inserted into the map, but it is fragile. Truth be told, the idea of associating annotations with instances is fragile in itself, so this is likely the least of your worries.


If you want to ensure that the most recently constructed MyConfiguration is accessible like this, you could put the above in it's constructor, like so:

@MyConfig
class MyConfiguration {
  public MyConfiguration() {
    // note this is potentially dangerous, as this isn't finished constructing
    // yet so be very cautious of this pattern, even though it might seem cleaner
    annotationMap.put(MyConfig.class, this);
  }
}

Now you can be confident that, if a MyConfiguration instance exists, it is accessible from annotationMap by its annotated type.


As I hinted above however, I suspect neither of these are good solutions for you. And really the reason why is because annotations are not designed at all to let you refer to instances; they are instead meant to let you know things about an instance once you already have one. So let me ask you, why do you think you need to lookup an object by its annotation? Is there another pattern you can use instead?

I suspect what you're really trying to build is a Singleton - you expect your runtime to have exactly one instance of MyConfiguration, and you want all your code to easily access it. A standard pattern for this is:

@MyConfig
class MyConfiguration {
  private static MyConfiguration INSTANCE = null;

  public static MyConfiguration getInstance() {
    // note this is not thread-safe
    // see the above link for several thread-safe modifications
    if(INSTANCE == null) {
      INSTANCE = new MyConfiguration();
    }
    return INSTANCE;
}

This lets any code call MyConfiguration.getInstance() and be able to access the instance. That said, Singletons are generally considered bad practice (though less so than what you're describing). Ideally, you should be passing your configuration instance around to whatever classes or threads need it. Passing your references explicitly, rather than relying on a semi-magical cache or global state like a singleton, is far and away the "right" way to deal with the problem you're facing.

dimo414
  • 47,227
  • 18
  • 148
  • 244