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?
Related
I have created an enumerated class that contains 2 values. What I want is to create a controller that returns the enumerations that exist along with their values.
This is my Enum Class:
#Getter
public enum ModesEnum {
ASSOCIATED ("A", "Associated"), DISASSOCIATED ("D", "Disassociated");
private String key;
private String value;
private ModesEnum(String key, String value) {
this.key = key;
this.value = value;
}
#JsonValue
public String getValor() {
return value;
}
#JsonValue
public String getKey() {
return key;
}
private static final Map<String, String> mapClassEnum;
static {
mapClassEnum = new HashMap<>();
Arrays.stream(values()).forEach(elem -> {
mapClassEnum.put(elem.getValue(), elem.getKey());
mapClassEnum.put(elem.getValue(), elem.getValor());
});
}
My Controller class:
#GetMapping(value = "/modesEnum")
public ResponseEntity<ModesEnum[]> getAll(){
return new ResponseEntity<>(ModesEnum.values(), null, HttpStatus.OK);
}
however when executing the controller it gives me the following error:
Problem with definition of AnnotedClass ModesEnum Multiple 'as-value' properties defined ModesEnum #getKey() vs ModesEnum [0]
How can I return in my controller something like this JSON?:
{
{ key: "A", value : "Associated"},
{ key: "D", value : "Disassociated"}
}
The JsonValue documentation says that only one method may be annotated with #JsonValue.
At most one method of a Class can be annotated with this annotation; if more than one is found, an exception may be thrown.
You can try to serialize both key and value in a toString() method (annotate toString() with #JsonValue).
Another option might be to use #JsonProperty on your enum instances:
#JsonProperty("associated")
ASSOCIATED ("A", "Associated"),
#JsonProperty("disassociated")
DISASSOCIATED ("D", "Disassociated");
I'm new to Java and trying to parse an XML file with objects having ENUM parameters as well. One of the ENUMs have a value as well. And at parsing I get error message (java.lang.IllegalArgumentException: No enum constant com.codecool.enums.AreaToUse.4).
the ENUM is
public enum AreaToUse {
TRAFICH(6),
TRAFICM(5),
HOMEH(4),
HOMEL(3);
private final int qualified;
AreaToUse(int qualified) {
this.qualified = qualified;
}
public int getQualified() {
return qualified;
}
}
the xml
<Lumber name="pineLong" producer="Nati" load="M" value="17.3"
qualified="4" length="3200" width="350" thickness="22"
species="pine"/>
and the parsing
for (int i = 0; i < lumbers.getLength(); i++) {
current = (Element) lumbers.item(i);
result.add(new Lumber(current.getAttribute("name"),
current.getAttribute("producer"),
Load.valueOf(current.getAttribute("load")),
Double.parseDouble(current.getAttribute("value")),
AreaToUse.valueOf(current.getAttribute("qualified")),
Integer.parseInt(current.getAttribute("length")),
Integer.parseInt(current.getAttribute("width")),
Integer.parseInt(current.getAttribute("thickness")),
current.getAttribute("species")));
}
my expected outcome is
pineLong, Nati, M, 17.3, 4, 3200, 350, 22, pine
actual return is
java.lang.IllegalArgumentException: No enum constant com.codecool.enums.AreaToUse.4
You have to write a method which returns the right Enum by the qualified value because valueOf searches an Enum by the given String. That is why you get the message No enum constant com.codecool.enums.AreaToUse.4. You have no AreaToUse called 4.
Try this:
public enum AreaToUse {
...
public static AreaToUse byQualified(int qualified) {
AreaToUse returnValue = null;
for(AreaToUse areaToUse : values()) {
if(areaToUse.getQualified() == qualified) {
returnValue = areaToUse;
}
}
return returnValue;
}
}
Instead I would recommend to create a map which maps qualified value to the area enum:
public enum AreaToUse {
private static final Map<Integer, AreaToUse> MAPPING = new HashMap<>();
static {
for(AreaToUse areaToUse : values()) {
MAPPING.put(areaToUse.getQualified(), areaToUse);
}
}
public static AreaToUse byQualified(int qualified) {
return MAPPING.get(qualified);
}
}
You should have a utility method like valueOfInt in ENUM AreaToUse which will convert your qualified int to a corresponding ENUM value.
public static AreaToUse valueOfInt(int i) {
return Arrays.stream(AreaToUse.values())
.filter(e -> e.getQualified() == i)
.findFirst()
.orElse(null);
}
And use it like:
AreaToUse.valueOfInt(current.getAttribute("qualified"))
If your current.getAttribute("qualified") returns a String then parse it to integer.
AreaToUse.valueOfInt(Integer.parseInt(current.getAttribute("qualified")))
Is it possible to get the variable which is annotated? I have a variable like this below:
#Flag
FlagElements flagElements = new FlagElements("key1", "type1", "value1", "desc1");
FlagElements is defined as below:
public class FlagElements<T>{
public String key;
public String type;
public T value;
public String description;
public FlagElements(String key, String type, T value, String description) {
this.key = key;
this.type = type;
this.value = value;
this.description = description;
}
}
I want to retrieve the value of flagElements. Is it possible?
You can achieve this using reflection on your class fields this way you can check if field are annotated with #Flag for instance, bellow a simple example :
for(Field field : TestObject.class.getDeclaredFields())
{
if (field.isAnnotationPresent(Flag.class))
{
Object value = field.get(objectInstance);//objectInstance is an instance of FlagElements, you can instanciate it using the new operator if you know already know the class type or use reflection if you don't know what you'll have as a class.
}
}
But make sure your Flag annotation has RetentionPolicy.RUNTIME
I'm generating JSON using the Gson library. I'm attempting to generate JSON like:
{"Plaintext":{"type":"List","value":["1","2","3","4"]},"SINGLE_FUNCTION":{"value":"1"},"IN_FLOW":{"value":10}}
However, the JSON that is appearing is..
{"Plaintext":{"type":"List","value":["1","2","3","4"]},"SINGLE_FUNCTION":{"value":"1"},"IN_FLOW":{"value":{"value":10}}}
The problem, I found is that when my objects are being created, an Integer object is being stored. This is because of the type of the mapping is Object, which means the int type that I'm storing is automatically wrapped to type Integer and Gson is rendering the only non-null value, value inside the Integer class.
My question is, is there a way of having Gson render an Integer object as if it were a primitive type int?
Edit
So, The whole JSON is a Map. This Map is defined as:
private Map<String, ParameterWrapper> parameterMap;
The class ParameterWrapper looks like this:
public class ParameterWrapper<T> {
private String type;
private T value;
public ParameterWrapper(String type, T value) {
this.type = type;
this.value = value;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
I suspect that because I'm not specifying a type T for ParameterWrapper, it's defaulting to Object, which is why Gson is outputting it as an Object and not an int, despite it being an instance of Integer.
This sample code (with lombok #Data and guava Lists):
package so28235867;
import com.google.common.collect.Lists;
import com.google.gson.Gson;
import lombok.Data;
import java.util.List;
public class Foo {
public static void main(final String[] args) {
final Root root = Root.of(Plaintext.of("List", Lists.newArrayList("1", "2", "3", "4")), new Value<String>("1"), new Value<Integer>(10));
System.out.println(new Gson().toJson(root));
}
#Data(staticConstructor = "of")
// TODO: tweak JSON serialisation to respect naming convention
static class Root {
private final Plaintext Plaintext;
private final Value<String> SINGLE_FUNCTION;
private final Value<Integer> IN_FLOW;
}
#Data(staticConstructor = "of")
static class Plaintext {
private final String type;
private final List<String> value;
}
#Data
static class Value<T> {
private final T value;
}
}
outputs:
{"Plaintext":{"type":"List","value":["1","2","3","4"]},"SINGLE_FUNCTION":{"value":"1"},"IN_FLOW":{"value":10}}
And that looks like what you want. So you probably have an error in the definition of your object hierarchy.
Change this,
public T getValue() {
return value;
}
to,
public T getValue() {
if( value instanceOf Integer ) {
return value.intValue();
}
return value;
}
My question is, is there a way of having Gson render an Integer object as if it were a primitive type int?
You can manually add the IN_FLOW (or any primitive) value as Integer primitive value.
jsonObject.add("IN_FLOW",new JsonPrimitive(obj.getInFlow()));
Is there a way to bind an Enum attribute and not enum constant with Jpa column.
I have a enum like this:
public enum Type{
TYPE1("type1"),
TYPE2("type2);
private String enumValue;
Type(String enumValue){
this.enumValue = enumValue;
}
public String getValue(){
return enumValue;
}
}
And entity like this:
public class TestEntity{
#Enumerated(EnumType.STRING)
private Type type;
}
My entity always bind with enum constant i.e. TYPE1 and not with enumValue i.e. "type1". I could not find a way to do that. I am wondering is that is even possible with JPA.
Thanks,
You can do that with a hibernate-proprietary custom type (if you use Hibernate) or, if you use a JPA 2.1 implementation, with the new Convert annotation. Here's an article showing an example
#Convert(converter = TypeConverter.class)
private Type type;
...
#Converter
public class TypeConverter implements AttributeConverter<Type, String> {
#Override
public String convertToDatabaseColumn(Type attribute) {
return attribute.getValue();
}
#Override
public Type convertToEntityAttribute(String dbData) {
return Type.fromValue(dbData);
}
}