Enum in Annotations - java

I have an annotation I can't change which expects two String arguments.
I'd like to use it like this:
#RequestMapping( MyUrls.FOO.a, MyUrls.FOO.b )
This is how I imagined implementing it
public enum MyUrls {
FOO("a", "b"),
BAR("c", "d");
public String a, b;
MyUrls(String a, String b) {
this.a = a;
this.b = b;
}
}
This doesn't work since a or b can't be statically resolved.
What alternatives do I have which are nicer than:
class MyUrls {
public static String FOO_A = "";
public static String FOO_B = "";
// ...
}

Although your question does not look like a question but as a declaration, I agree with you.
You cannot use enum members when you are defining annotations. Only "real" constants, i.e. static final fields and constant expressions are applicable. So, there is no good alternative right now.

You could use a static inner class to group your strings.
class MyUrls {
public static final class Foo{
public static final String A = "";
public static final String B = "";
// ...
}
}
//works as
MyUrls.Foo.A

Related

Can I use the name of the enum constant in the constructor?

Say I have an enum of Things with names:
public enum Thing {
THINGA, THINGB, THINGC, THINGD,
THINGE("Thing E"),
;
public final String name;
private Thing(String pname) {
name = pname;
//...
}
private Thing() {
// See question
}
}
Say I want to do the same thing I did with THINGE for all my other Things, except I want the default name to be the same as that of the enum constant itself, e.g.:
private Thing() {
this(/* the name of the constant itself */);
}
Essentially, I want the implied value of pname to be "THINGA" for THINGA, "THINGB" for THINGB, "THINGC" for THINGC, "THINGD" for THINGD, etc. Using either toString() or name(), the compiler yells:
error: cannot reference this before supertype constructor has been called
Is there any way to avoid this?
Specifically, I include the names for the sake of the user. It feels more natural to look at "Thing E" rather than "THINGE", but its much easier for me to program if I can write a method to turn "THINGA" into "Thing A" and use that in the constructor.
You don't need to give a parameter to the constructor for this, using name() and a bit of String manipulation should get you there.
public static void main(String[] args) {
for (Thing value : Thing.values()) {
System.out.println("value.name = " + value.name);
}
}
public enum Thing {
THINGA,
THINGB,
THINGC,
THINGD,
THINGE;
public final String name;
Thing() {
this.name = name().replace("THING", "Thing ");
}
}
Prints
value.name = Thing A
value.name = Thing B
value.name = Thing C
value.name = Thing D
value.name = Thing E
I believe from your question that you don't want to change what .name() returns, but introduce another field on your enum values which defaults to .name().
You can do this:
public class Comparison
{
public enum Foo {
A, B, C("My C");
private final String myName;
Foo(String myName) {
this.myName = myName;
}
Foo() {
myName = this.name();
}
public String getMyName() {
return myName;
}
}
public static void main(String[] args)
{
System.out.println(Arrays.stream(Foo.values()).map(e -> e.getMyName()).collect(Collectors.joining("\n")));
}
}

Is there any way to pass a variable while initializing an enum instead of passing actual value in java?

I need to pass a class variable to an enum while initializing it .But the class variable is not accessible while initializing the enum . So how can this be achieved ?
I tried passing variable of another class, same class where the enum resides . Both didn't work.
public class ComponentConstants {
public Constants constants = Constants.getInstance();
enum FIELDS_RESOURCES {
//instead of text i want to use constants.data_type.text. But I was not able to.
SourcetType(true, "text", "Source Type", "source_type", 255, false); //No I18N
private VOCFIELDS_RESOURCES(boolean isCustomField, String data_type, String field_label, String api_name, int length, boolean isVisible) {
this.isCustomField = isCustomField;
this.data_type = data_type;
this.field_label = field_label;
this.api_name = api_name;
this.length = length;
this.isVisible = isVisible;
}
}
}
In the above I want to use the value from constants since if there is any change there ,it should be reflected in my code too . Single point of constants , but i was not able to use it. How can this be achieved and why is it not allowing to use other variables? Thanks!
public class Main {
public enum Enumeration {
Test(Constants.a, Constants.b); // can refer to constant "a" & "b" static variables
private final String a;
private final String b;
Enumeration(String a, String b) {
this.a = a;
this.b = b;
}
}
public static class Constants {
static String a = "a";
static String b = "b";
}
}
If you utilize static fields as constants, they can be referenced within enumeration constructors. More details here regarding enum fields.

Correct way to use static parameters in Android

I am pretty new in Android and I do not know how is the proper way to manage static constants. I mean, I need to use several constants (such as COMMAND_BACK = 100) in several Java classes and activities. It is not beautiful to declare them as attributes in each single activity so, what is the correct way to do this?
I though about declaring them in strings.xml, but it does not seem suitable neither...
Thanks in advance.
You can make a class like this :
public final class AppConstants {
//put all the constant here
// Eg :
public static final int SPLASH_TIME = 1000;
}
The disadvantage by declaring it in a resource.xml file is that you need a context to receive the value. This is fine as long as you need those values inside a context class otherwise you have to pass one around.
The elegant solution would be extending the Application class since the android os itself uses static fields that way.
Declare
public final class ConstantClass {
public final static int COMMAND_BACK = 100;
}
Usage
int num = ConstantClass.COMMAND_BACK;
Add a Constants class to the project
public class Constants {
public static final String STRING1 = "First String";
public static final String STRING2 = "Second String";
public static final int INTEGER1 = 1;
public static final float FLOAT1 = 0.1f;
}
// Use
textView.setText(Constants.STRING1);
Create a common interface where you can declare all the constants.Constants can further be grouped here to make it mode clean.
public interface Constants {
public interface XYZ{
public static final int A= 1;
public static final int B= 2;
}
public interface REPORT_TYPE_FLAGS{
public static final String C= "0";
public static final String D= "1";
}
}
Another elegant way is to define a constant class with other inner subclasses
`private final class Constant {
public static class TypeOne {
public static final String NAME = "Type 1";
public static final int CODE = 1;
}
public static class TypeTwo {
public static final String NAME = "Type 2";
public static final int CODE = 2;
}
}
`
And you can access it in this way
`String typeOneName = Constant.TypeOne.NAME;
int typeTwoCode = Constant.TypeTwo.CODE;
`

How to enable enum inheritance

I'm writing a library, which has a predefined set of values for an enum.
Let say, my enum looks as below.
public enum EnumClass {
FIRST("first"),
SECOND("second"),
THIRD("third");
private String httpMethodType;
}
Now the client, who is using this library may need to add few more values. Let say, the client needs to add CUSTOM_FIRST and CUSTOM_SECOND. This is not overwriting any existing values, but makes the enum having 5 values.
After this, I should be able to use something like <? extends EnumClass> to have 5 constant possibilities.
What would be the best approach to achieve this?
You cannot have an enum extend another enum, and you cannot "add" values to an existing enum through inheritance.
However, enums can implement interfaces.
What I would do is have the original enum implement a marker interface (i.e. no method declarations), then your client could create their own enum implementing the same interface.
Then your enum values would be referred to by their common interface.
In order to strenghten the requirements, you could have your interface declare relevant methods, e.g. in your case, something in the lines of public String getHTTPMethodType();.
That would force implementing enums to provide an implementation for that method.
This setting coupled with adequate API documentation should help adding functionality in a relatively controlled way.
Self-contained example (don't mind the lazy names here)
package test;
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<HTTPMethodConvertible> blah = new ArrayList<>();
blah.add(LibraryEnum.FIRST);
blah.add(ClientEnum.BLABLABLA);
for (HTTPMethodConvertible element: blah) {
System.out.println(element.getHTTPMethodType());
}
}
static interface HTTPMethodConvertible {
public String getHTTPMethodType();
}
static enum LibraryEnum implements HTTPMethodConvertible {
FIRST("first"),
SECOND("second"),
THIRD("third");
String httpMethodType;
LibraryEnum(String s) {
httpMethodType = s;
}
public String getHTTPMethodType() {
return httpMethodType;
}
}
static enum ClientEnum implements HTTPMethodConvertible {
FOO("GET"),BAR("PUT"),BLAH("OPTIONS"),MEH("DELETE"),BLABLABLA("POST");
String httpMethodType;
ClientEnum(String s){
httpMethodType = s;
}
public String getHTTPMethodType() {
return httpMethodType;
}
}
}
Output
first
POST
Enums are not extensible. To solve your problem simply
turn the enum in a class
create constants for the predefined types
if you want a replacement for Enum.valueOf: track all instances of the class in a static map
For example:
public class MyType {
private static final HashMap<String,MyType> map = new HashMap<>();
private String name;
private String httpMethodType;
// replacement for Enum.valueOf
public static MyType valueOf(String name) {
return map.get(name);
}
public MyType(String name, String httpMethodType) {
this.name = name;
this.httpMethodType = httpMethodType;
map.put(name, this);
}
// accessors
public String name() { return name; }
public String httpMethodType() { return httpMethodType; }
// predefined constants
public static final MyType FIRST = new MyType("FIRST", "first");
public static final MyType SECOND = new MyType("SECOND", "second");
...
}
Think about Enum like a final class with static final instances of itself. Of course you cannot extend final class, but you can use non-final class with static final instances in your library. You can see example of this kind of definition in JDK. Class java.util.logging.Level can be extended with class containing additional set of logging levels.
If you accept this way of implementation, your library code example can be like:
public class EnumClass {
public static final EnumClass FIRST = new EnumClass("first");
public static final EnumClass SECOND = new EnumClass("second");
public static final EnumClass THIRD = new EnumClass("third");
private String httpMethodType;
protected EnumClass(String name){
this.httpMethodType = name;
}
}
Client application can extend list of static members with inheritance:
public final class ClientEnum extends EnumClass{
public static final ClientEnum CUSTOM_FIRST = new ClientEnum("custom_first");
public static final ClientEnum CUSTOM_SECOND = new ClientEnum("custom_second");
private ClientEnum(String name){
super(name);
}
}
I think that this solution is close to what you have asked, because all static instances are visible from client class, and all of them will satisfy your generic wildcard.
We Fixed enum inheritance issue this way, hope it helps
Our App has few classes and each has few child views(nested views), in order to be able to navigate between childViews and save the currentChildview we saved them as enum inside each Class.
but we had to copy paste, some common functionality like next, previous and etc inside each enum.
To avoid that we needed a BaseEnum, we used interface as our base enum:
public interface IBaseEnum {
IBaseEnum[] getList();
int getIndex();
class Utils{
public IBaseEnum next(IBaseEnum enumItem, boolean isCycling){
int index = enumItem.getIndex();
IBaseEnum[] list = enumItem.getList();
if (index + 1 < list.length) {
return list[index + 1];
} else if(isCycling)
return list[0];
else
return null;
}
public IBaseEnum previous(IBaseEnum enumItem, boolean isCycling) {
int index = enumItem.getIndex();
IBaseEnum[] list = enumItem.getList();
IBaseEnum previous;
if (index - 1 >= 0) {
previous = list[index - 1];
}
else {
if (isCycling)
previous = list[list.length - 1];
else
previous = null;
}
return previous;
}
}
}
and this is how we used it
enum ColorEnum implements IBaseEnum {
RED,
YELLOW,
BLUE;
#Override
public IBaseEnum[] getList() {
return values();
}
#Override
public int getIndex() {
return ordinal();
}
public ColorEnum getNext(){
return (ColorEnum) new Utils().next(this,false);
}
public ColorEnum getPrevious(){
return (ColorEnum) new Utils().previous(this,false);
}
}
you could add getNext /getPrevious to the interface too
#wero's answer is very good but has some problems:
the new MyType("FIRST", "first"); will be called before map = new HashMap<>();. in other words, the map will be null when map.add() is called. unfortunately, the occurring error will be NoClassDefFound and it doesn't help to find the problem. check this:
public class Subject {
// predefined constants
public static final Subject FIRST;
public static final Subject SECOND;
private static final HashMap<String, Subject> map;
static {
map = new HashMap<>();
FIRST = new Subject("FIRST");
SECOND = new Subject("SECOND");
}
private final String name;
public Subject(String name) {
this.name = name;
map.put(name, this);
}
// replacement for Enum.valueOf
public static Subject valueOf(String name) {
return map.get(name);
}
// accessors
public String name() {
return name;
}

condition for initializing constants in interface

I have an interface where I have defined constants used across application. I have a scenario where I need to initialize constants based on condition.
for eg , something like,
if(condition){
public static final test = "some value";
}
Is this possible.
Interfaces are to be implemented. They should not be used as carriers for constants. If you need such a thing you might consider a final class with a private constructor.
What you seem to want is a global variable or singleton, which are rather problematic designs, or something like a c preprocessor directive, dynamically evaluated at compile time.
So consider if it is really a constant you need - something which is defined at compile (or class loading) time.
Interface contains no code.
Split your interface in many specific interfaces declaring and initializing their own constants.
This will follow the Interface Segregation Principle where a class doesn't have to be bored by some useless constants or methods.
Of course, Java let classes implement several interfaces at once. So if you have specific interfaces to mix up for one concrete class, this would be pretty easy.
You can set static final variable with condition in following way:
public class Test {
public static final String test;
static {
String tmp = null;
if (condition) {
tmp = "ss";
}
test = tmp;
}
}
You can do it in one line, also in interface with:
public static final String test = condition ? "value" : "other value";
This can be another reason why Interface constants are bad. You can simply use enums Like below.
public enum Const {
SAMPLE_1(10), SAMPLE_2(10, 20);
private int value1, value2;
private Const(int value1, int value2) {
this.value1 = value1;
this.value2 = value2;
}
private Const(int value1) {
this.value1 = value1;
}
//Value based on condition
public int getValue(boolean condition) {
return condition == true ? value2 : value1;
}
//value which is not based on conditions
public int getValue() {
return value1;
}
}
public interface InitializeInInterface {
public static final String test = Initializer.init();
static class Initializer {
public static String init() {
String result = "default value";
InputStream is = InitializeInInterface.class.getClassLoader().getResourceAsStream("config.properties");
Properties properties = new Properties();
try {
properties.load(is);
} catch (IOException e) {
e.printStackTrace();
}
if ("bar".equals(properties.getProperty("foo"))) {
result = "some value";
}
return result;
}
}
}

Categories

Resources