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.

12
  • 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);? Commented Aug 25, 2014 at 21:29
  • 3
    Find it where? Somewhere in the heap? This's isn't really possible. Commented Aug 25, 2014 at 21:29
  • This may be your answer here: stackoverflow.com/questions/259140/… In particular pay attention to the comments of the accepted answer. I think this is the functionality you are looking for. Commented Aug 25, 2014 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. Commented Aug 25, 2014 at 21:37
  • 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). Commented Aug 25, 2014 at 21:38

1 Answer 1

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.