1

Having something like:

import com.example.test.classA;
import com.example.test.classB;
import com.example.test.classC;

public class MyClass {
    ...
    Flavors p = Flavors.VANILLA;
    ...
    String flavorChoice = "Flavors.CHOCOLATE";
    ...
}

where Flavors is an enum declared in one of the imported classes:

public enum Flavors { CHOCOLATE, VANILLA, LEMON };

How can I get a value, using reflection, from the string flavorChoice?
Do not assume I know in which imported class Flavors is declared.
Do not even assume that Flavors is accessible from within MyClass.

CLARIFICATIONS
The string flavorChoices should produce an Object, the object may be, in the example above it is, of type Flavors. But it also may refer to other constants in other enums:

String flavorChoice = "ExtraFlavors.MENTA";
String flavorChoice = "ExoticFlavors.CHALK";
String flavorChoice = "AnyEmun.ANYCONSTANT";

I don't know what the string contents are until runtime. I want to be able to:

  1. Check the referred enum indeeed exists and is accessible from MyClass
  2. Get the referred enum constant and put it in an Object
ilomambo
  • 8,290
  • 12
  • 57
  • 106
  • 3
    If you don't know which particular `Flavors` class to refer to, then how could this ever work? – Oliver Charlesworth Jun 09 '13 at 15:14
  • Maybe [this question](http://stackoverflow.com/q/492184/732016), with some adaptations, could be of use? – wchargin Jun 09 '13 at 15:16
  • Realistically, though, why wouldn't you know where the class `Flavors` is declared? Even if you get it with reflection, you'd only be able to store it as an `Object` (or an `Enum>`) if you haven't imported it... – wchargin Jun 09 '13 at 15:17
  • @OliCharlesworth That's why I put the line `Flavors p = Flavors.VANILLA` in the example, to show that without reflection I can use `Flavors` without knowing exactly where it is declared. For the sake of simplicity, if it helps you to formulate an answer, assume there is only one `Flavors` declared in the system. – ilomambo Jun 09 '13 at 15:18
  • @WChargin Ralistically, I know where `Flavors` is declared. What I don't know beforehand is the string `flavorChoice`, which can refer to any `enum` that is visible in that scope. It Even can refer to some `enum` that is not accessible there, in which case I want to call a `RuntimeException`. – ilomambo Jun 09 '13 at 15:25

2 Answers2

0

If string is re-defined as following:

String flavorChoice = "CHOCOLATE";

you even do not need reflection. Just use Flavors.valueOf(flavorChoice).

In your case you can say:

String choice = "Flavors.CHOCOLATE";
String[] fragments = choice.split("\\."); 
Enum.valueOf(Class.forName(fragments[0]), fragments[1]);

Class.forName(fragments[0]) will return you your enum's class, Enum.valueOf() returns the element of the enum.

EDIT: If in real-world case your classes belong to package you should improve the parsing by replacing split() to something else.

AlexR
  • 114,158
  • 16
  • 130
  • 208
  • As long as I need to provide the class for `Class.forName()` this does not help me. I need a way to check if `Flavors` is a known class in the scope (note that *"known class in the scope"* is much broader than checking for the current object subclasses, it may be a class is know because of `import` or because some parent class up in the hierarchy declared it) – ilomambo Jun 09 '13 at 15:32
  • @ilomambo: AFAIK, there is no information about lexical scope available to the reflection mechanism. So it may be that what you're asking for is impossible. – Oliver Charlesworth Jun 09 '13 at 18:58
0

If you have access to the Flavors class, as suggested by the example, the valueOf method may be useful:

Returns the enum constant of this type with the specified name. The string must match exactly an identifier used to declare an enum constant in this type. (Extraneous whitespace characters are not permitted.)

Thus:

Flavor f = Flavors.valueOf("VANILLA");

If your question is how to extract VANILLA from Flavors.VANILLA, you could try:

Flavor f = Flavors.valueOf("Flavors.VANILLA".replaceAll("^.*\\.", ""));

where * is a greedy quantifier.

The advantage of using regex over split("\\.")[1] is that if the parameter came in with a greater qualification, like classA.Flavors.VANILLA or com.example.test.classA.Flavors.VANILLA, the regex would still work. Alternatively, you could use:

String[] parts = "Flavors.VANILLA".split("\\.");
String flavorPart = parts[parts.length - 1];
wchargin
  • 15,589
  • 12
  • 71
  • 110
  • better regex - it will work with `SomeClass.Flavors.VANILLA` too. – assylias Jun 09 '13 at 15:24
  • You should use it in your split too then – assylias Jun 09 '13 at 15:25
  • 1
    @assylias I added the `split` part to show that you can do it with even the simplest regex because some people don't like using complicated regex. If this were the case I actually think it would be better to do `java.util.regex.Pattern.quote(".").split(identifierString)` but maybe that's just me... – wchargin Jun 09 '13 at 15:27
  • @WChargin Addition to my reply comment to you in the original question. If I could use `Flavors` that would be fine, but note that I wrote *"Do not even assume that Flavors is accessible from within MyClass"*. Maybe the question is oversimplified, I will add some clarifications there. – ilomambo Jun 09 '13 at 15:37
  • If you can do `Flavors p = Flavors.VANILLA` then you can call `Flavors.valueOf` ; am I missing something? – wchargin Jun 09 '13 at 17:01