How to define static constants in a Java enum? - java

Is there any way to define static final variables (effectively constants) in a Java enum declaration?
What I want is to define in one place the string literal value for the BAR(1...n) values:
#RequiredArgsConstructor
public enum MyEnum {
BAR1(BAR_VALUE),
FOO("Foo"),
BAR2(BAR_VALUE),
...,
BARn(BAR_VALUE);
private static final String BAR_VALUE = "Bar";
#Getter
private final String value;
}
I got the following error message for the code above: Cannot reference a field before it is defined.

As IntelliJ IDEA suggest when extracting constant - make static nested class. This approach works:
#RequiredArgsConstructor
public enum MyEnum {
BAR1(Constants.BAR_VALUE),
FOO("Foo"),
BAR2(Constants.BAR_VALUE),
...,
BARn(Constants.BAR_VALUE);
#Getter
private final String value;
private static class Constants {
public static final String BAR_VALUE = "BAR";
}
}

public enum MyEnum {
BAR1(MyEnum.BAR_VALUE);
public static final String BAR_VALUE = "Bar";
works fine

public enum MyEnum {
// BAR1( foo), // error: illegal forward reference
// BAR2(MyEnum.foo2), // error: illegal forward reference
BAR3(MyEnum.foo); // no error
public static final int foo =0;
public static int foo2=0;
MyEnum(int i) {}
public static void main(String[] args) { System.out.println("ok");}
}
This can be done without an inner class for the constant.

Maybe you should considering breaking this enum into two fields: an enum and an int:
#RequiredArgsConstructor
public enum MyEnum {
BAR("Bar"),
FOO("Foo")
#Getter
private final String value;
}
And then use:
private MyEnum type;
private int value;
(You can put that into a class or not, whether it makes sense to you)

Related

Java Enum Accepted Values

An enum data type is defined as an attribute of a class.
public class Foo {
public enum Direction {
NORTH("north"),
EAST("east"),
SOUTH("south");
public final String label;
private Direction(String label) {
this.label = label;
}
}
private Directory direction;
...
}
When I parse a Json data to match the class, I get an error
String "east": not one of the values accepted for Enum class: [NORTH, EAST, SOUTH, WEST]
This problem can be resolved by changing the enum data to all low case. If I want to use the Java enum data type convention, what is needed to resolve the problem?
If you are using Jackson to deserialise the Foo class, you could:
public class Foo {
public enum Direction {
NORTH("north"),
EAST("east"),
SOUTH("south");
#JsonValue
public final String label;
private Direction(String label) {
this.label = label;
}
}
private Direction direction;
// getter, setter for direction must exist
}
// then deserialise by:
ObjectMapper mapper = new ObjectMapper();
String json = "{\"direction\":\"north\"}";
Foo f = mapper.readValue(json, Foo.class);
This will result in a Foo object with a Direction.NORTH field.
For other possibilities when using Jackson check https://www.baeldung.com/jackson-serialize-enums

sonar custom rule check java collection type is unknownSymbol

Collection type always return 'unknownSymbol' in a custom sonar check rule class.
//demo class
public class SaasConstantNameCheckCase {
private static final long serialVersionUID;
private final String title;
public static final Integer maxSize = 1111;// Noncompliant
private static List list = new ArrayList<>();
private static HashMap<String, String> map = new HashMap<>();
}
// custom rule class
#Override
public void visitVariable(VariableTree tree) {
VariableSymbol symbol = (VariableSymbol) tree.symbol();
String type = symbol.type().name();
System.out.println("type->"+type);
}
// test result
type->long
type->String
type->Integer
type->!unknownSymbol!
type->!unknownSymbol!
Why?
SonarJava will show this unknownSymbol! string when it fails to resolve the actual type symbols.
In this particular case, you should either use fully qualified types java.util.List and java.util.HashMap, or import them.

Java outer class static initialization

I have a problem with Java static initialization. What I want to do is some type checking with generic constants and to translate between types and type names. So I have some typed constants in interface MC and a hash map in inner class Type to translate names to types. Now when I call MC.Type.getValue("MInteger") the inner class Type is initialized but not the static constants in the outer class MC so the return value is null. How can I get Java to initialize these constants? I could do
static { Type<?> dummy = MC.MBoolean; }
in class Type but isn't there some better way to do this. Or am I doing this totally wrong.
import java.util.HashMap;
import java.util.Map;
interface MC {
public static final Type<Boolean> MBoolean = new Type<>("MBoolean");
public static final Type<Integer> MInteger = new Type<>("MInteger");
public static class Type<T> {
private static final Map<String, Type<?>> types = new HashMap<>();
private final String name;
private Type(String name) {
this.name = name;
types.put(name, this);
}
public String getName() {
return name;
}
public static Type<?> getValue(String name) {
return types.get(name);
}
}
}
public class Main {
public static void main(String[] args) {
System.out.println(MC.Type.getValue("MInteger"));
MC.MBoolean.getName();
System.out.println(MC.Type.getValue("MInteger"));
}
}
Since all Type instances are included in your MC class, a very direct approach to solving this problem would be to move registration of the class with the Type.types map from the constructor of Type to its static initializer:
private static final Map<String, Type<?>> types = new HashMap<>();
static {
types.put(MBoolean.getName(), MBoolean);
types.put(MInteger.getName(), MInteger);
}
private Type(String name) {
this.name = name;
// removed types.put(name, this); from here
}
Demo.
You can use either static initializer block:
private static final Map<String, Type<?>> types = new HashMap<>();
static {
types.put(MC.MBoolean.getName(), MC.MBoolean);
types.put(MC.MInteger.getName(), MC.MInteger);
}
or double brace initialization:
private static final Map<String, Type<?>> types = new HashMap<>() {{
put(MC.MBoolean.getName(), MC.MBoolean);
put(MC.MInteger.getName(), MC.MInteger);
}};
First curly braces creates new anonymous subclass of HashMap, second curly braces are instance initializer block which is executed at construction time (arg-less constructor for anonymous classes).
The Constructor won't initialize unless you explicitly call MC.MBoolean. so better you go with the Double brace initialization.
private static final Map<String, Type<?>> types = new HashMap<>() {
{
put(MC.MBoolean.getName(), MC.MBoolean);
put(MC.MInteger.getName(), MC.MInteger);
}
};

Assign an enum element to an annotation

I would like to use an enum element as a value of an annotation attribute (which requires a string value). Hence, I have created an interface holding the String constants:
public interface MyStringConstants {
public static final String COMPANY_LOGIN = "Company Login";
public static final String COMPANY_LOGOUT = "Company Logout";
...
}
Furthermore I created the enum:
public enum MyEnumType implements MyStringConstants {
COMPANY_CONFIGURATION_READ(MyStringConstants.COMPANY_CONFIGURATION_READ),
COMPANY_CONFIGURATION_WRITE(MyStringConstants.COMPANY_CONFIGURATION_WRITE),
...;
private final String value;
private MyEnumType(final String myStringConstant) {
this.value = myStringConstant;
}
public String getValue() {
return this.value.toString();
}
public static MyEnumType getByValue(final String value){
for(final MyEnumType type : values()){
if( type.getValue().equals(value)){
return type;
}
}
return null;
}
}
There exists an annotation:
#DeviceValidatorOperation(operationType=MyStringConstants.COMPANY_CONFIGURATION_READ)
I would like to define the enum as mentioned above to put as a value for the annotation's operationType attribute. Using my enum from above results in this way:
#DeviceValidatorOperation(operationType=MyEnumType.COMPANY_CONFIGURATION_READ.getValue())
results in Eclipse complaining:
The value for annotation attribute DeviceValidatorOperation.operationType must be a constant expression
How can I achieve to use an enum element as a value for an annotation's attribute?

Java 1.4 Factory Question

I have a factory, and I want to restrict the possible values that may be passed into the get method.
public static class FooFactory{
public static final String TYPE1= "type1";
public static Foo getFoo(String type){
switch(type){
case "type1":
return new Type1();
}
}
}
To use this:
FooFactory.getFoo(FooFactory.TYPE1);
I'd like to restrict the parameters that may be passed in. Is an idea to make a Type abstract class, then subclass and use Type as the parameter?
Don't subclass it, just create a Type class with a private constructor that takes a stirng parameter, and define public Type constants.
Something like this.
public final class Type {
public static final Type FOO = new Type( "foo" );
public static final Type BAR = new Type( "bar" );
private String type;
private Type( String type ) {
this.type = type;
}
public String getType() { return type; }
}

Categories

Resources