Reputation: 2757
The title may be a bit hard to understand, but let me just briefly describe my problem.
Let's assume I have an annotation like this:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Identifier {
}
Now, I make a class which annotates any of its fields with it:
public class Student {
private String name;
private String surname;
@Identifier
private String idNumber;
...
}
Finally, at runtime I want to create a Map
with the key type of typeof(field annotated with @Identifier)
and the value type of Student
. Note that any field can be annotated with @Identifier
.
Any ideas?
EDIT
Ok, let me clarify this a bit:
class Student {
private String name;
private String surname;
@Identifier
private String idNumber;
}
class Foo {
@Identifier
private Integer x;
}
// Now, what I want to have are two maps:
SortedMap students; // key type: String
// value type: Student
SortedMap foos; // key type: Integer
// value type: Foo
Thanks in advance!
Upvotes: 3
Views: 609
Reputation: 280112
I'm still not exactly sure what you want to do.
at runtime I want to create a Map with the key type of typeof(field annotated with @Identifier) and the value type of Student
You can create a raw Map
or a Map<Object, Object>
. You can get the type of the field annotated with @Identifier
. I'm not sure what you mean by value type of Student so I'll assume you mean the type Student
, ie. its Class
object.
public static void main(String[] args) throws Exception {
Class<?> clazz = Student.class;
Map<Object, Object> map = new HashMap<>();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
Identifier annotation = field.getAnnotation(Identifier.class);
if (annotation != null) {
map.put(field.getType(), clazz);
}
}
System.out.println(map);
}
With your example class in your question, this prints
{class java.lang.String=class com.spring.Student}
So the annotated field type is mapped to the class type.
You won't be able to have a Map<String,Student>
though because you don't know the type String
(and possibly not even Student
) at compile time. You can try casting, but you're setting yourself up for a number of ClassCastException
s.
Upvotes: 1
Reputation: 30548
So you are going to have a method (myMethod
in my example) which will be passed objects which may hold a field annotated with @Identifier
.
Sorry to burst your bubble but there is no way to keep generic information at runtime. The closest you can get is having a Map<Field, Class<?>>
which holds key-value pairs with your desired type. This is how you do it:
public Map<Field, Class<?>> myMethod(Object obj) {
Map<Field, Class<?>> result = new HashMap<Field, Class<?>>();
for(Field field : obj.getClass().getDeclaredFields()) {
Identifier identifier = field.getAnnotation(Identifier.class);
if(identifier != null) {
result.put(field, obj.getClass());
return result;
}
}
return result;
}
In my example the result will either be an empty Map
or a Map
with one key-value pair. I suggest you should use a separate type for the result instead of a Map
. Of course you can tamper with the code if you want something other than a Field
for example you can use Field
's getType()
or getGenericType()
methods.
Upvotes: 0