Get the value of the annotated variable - java

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

Related

How to call class method by java annotation name with Jackson?

Wondering if there is a way to call the getter methods by the Jackson annotation property name (eg. "value") instead of the method name (eg. getName()) or point me to the right direction?
public class Person {
private String name;
#JsonProperty("value")
public String getName() {
return name;
}
#JsonProperty("value")
public void setSet(String name) {
this.name = name;
}
}
My goal is to call multiple methods by iterating trough a list of java annotation property names.
If you really want to identify and call the methods directly you could use reflection. Something like (with no exception management):
SomeObject object = ...;
Class<?> type = object.getClass();
for (Method method : type.getMethods()) {
JsonProperty property = method.getAnnotation(JsonProperty.class);
if (property != null && property.value().equals("value")) {
if (method.getParameterCount() == 0) {
Object value = method.invoke(object);
...
}
}
}
This is what I used as an answer by Allen D.
Map<String,Object> map = new ObjectMapper.convertValue(person, new TypeReference<Map<String,Object>>(){});
String s = (String) map.get("value");

Java iterate over class fields to create other class

I have a class like this:
public class Example {
private String a;
private Integer b;
private Boolean c;
private List<AnotherClass> d;
}
and I want to convert it to something like this:
[
{
name: "a",
value: "a value"
},
{
name: "b",
value: "1",
},
{
name: "c",
value: "true",
}
]
So, I create a class like this:
public class Test {
private String name;
private String value;
}
I want to have a method to iterate through the Example class so it will produce the Test class without including d attribute. How to achieve that?
This is something you can do easily with reflection. In the example below, I renamed class Test to Property because it represents a key-value pair. If you are happy with using whatever toString() returns as the value for a field, then the solution is pretty simple:
public class Property {
private final String name;
private final String value;
public Property(String name, String value) {
this.name = name;
this.value = value;
}
public static List<Property> toProperties(Object object, String... fieldNames)
throws ReflectiveOperationException
{
ArrayList<Property> properties = new ArrayList<>();
for( String fieldName : fieldNames ) {
Field field = object.getClass().getDeclaredField(fieldName);
properties.add(new Property(fieldName, field.get(object).toString()));
}
return properties;
}
public String toString() {
return String.format("%s: \"%s\"", name, value);
}
}
This sample requires you to specify the names of the desired fields explicitly, for example:
List<Property> properties = Property.toProperties(myExample, "a", "b", "c");
If you'd rather have the fields be auto-detected based on some criterion (for example all primitive and String-typed fields, then you could add this logic within toProperties and get rid of the varargs.
you would need to have some appropriate getters in class Example, and a proper constructor in class Test to initialize the object instance variables like
public Test (String name, int value) {
this.name = name;
this.value = value'
}
Then for each instance of class Example - lets say you have multiple of those in an array or list - you could iterate over them, retrieve the values you want via the getter methods, and initialize one Test object for each one, eg
List<Test> yourListOfTestInstances = new ArrayList<>();
for (Example exampleObject : yourExampleObjectsListOrArray) {
yourListOfTestInstances.add(new Test(exampleObject.getA() , exampleObject.getB()));
}
Then for each created Test instance inside your ArrayList, you could easily build your JSON as needed (even though I do not fully understand why you even need at all this intermediate Test class to do that)

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/jackson - #JsonValue/#JsonCreator and null

I have a Value class which holds a value:
public class Value {
protected final Object value;
#JsonValue
public Object getValue() {
return value;
}
#JsonCreator
public Value(final Object value) {
this.value = value;
}
}
This Value class is embedded as a field (amongst other fields) in a data class:
class Data {
protected final Value value;
#JsonProperty("value")
public Value getValue() {
return value;
}
...
#JsonCreator
public Data(#JsonProperty("value") final Value value, ...) {
this.value = value;
....
}
}
When the input JSON has null for the value field of a data object (see below for example), Data.value is null. I would like to have Data.value set to new Value(null). In other words, the data object must hold a non-null value object, which holds the null.
{
"value" : null,
...
}
What is the easiest way to achieve this? I could ofcourse alter the constructor of Data, but I am wondering if Jackson could resolve this automatically.
You can write a custom de-serializer and override the getNullValue() method according to your requirements e.g.
public final class InstantiateOnNullDeserializer
extends JsonNodeDeserializer
{
#Override
public JsonNode getNullValue()
{
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.convertValue(new Value(null), JsonNode.class);
return node;
}
}
and register it on the value field of your Data class
class Data {
#JsonDeserialize(using = InstantiateOnNullDeserializer.class)
protected final Value value;
#JsonProperty("value")
public Value getValue() {
return value;
}
#JsonCreator
public Data(Value value) {
this.value = value;
}
}
Note that you need to remove the #JsonProperty("value") to avoid argument type mismatch. By removing JsonProperty annotation you create a so-called "delegate creator",
Jackson will than first bind JSON into type of the argument, and then call a creator
I do not believe that this is possible without creating your own deserializer or modify the constructor (or #JsonCreator).
From a good old thread in the Jackson User Group:
#JsonProperty does not support transformations, since the data binding is based on incremental parsing and does not have access to full tree representation.
So, in order to avoid a custom deserializer I would do something along the lines of:
#JsonCreator
public Data(#JsonProperty("value") final String value) {
this.value = new Value(value);
}
Which is kind of the opposite of what you asked ;)

Gson Serializing the Integer object

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()));

Categories

Resources