I have a series of classes, which are unrelated. Each classs has one property with and #PrimaryKey (with getter and setter) that could be of any type. How can I use reflection to find which property of an instance of any class has the #PrimaryKey annotation - so I can get its value as a string.
The code doesn't know which type of class its being passed - it will just be of type "Object"
You can do something like this:
for (Field field : YourClass.class.getDeclaredFields()) {
try {
Annotation annotation = field.getAnnotation(PrimaryKey.class);
// what you want to do with the field
} catch (NoSuchFieldException e) {
// ...
}
}
If you are working with the instance of your class then you can do this to get its class object:
Class<?> clazz = instance.getClass();
so the first line becomes something like this:
instance.getClass().getDeclaredFields()
If you are in trouble you can always check out the official documentation. I believe it is quite good.
You can get all fields of a class and then iterate and find which field has your annotation:
Field[] fields = YourClass.class.getDeclaredFields();
for (Field field : fields) {
Annotation annot = field.getAnnotation(PrimaryKey.class);
if (annot != null) {
System.out.println("Found! " + field);
}
}
First of all you need to find all classes that may have the annotation in their members. This can be accomplished using Spring Framework ClassUtils:
public static void traverse(String classSearchPattern, TypeFilter typeFilter) {
ClassLoader classLoader = ClassUtils.getDefaultClassLoader();
ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver(classLoader);
Resource[] resources = null;
try {
resources = resourceResolver.getResources(classSearchPattern);
} catch (IOException e) {
throw new FindException(
"An I/O problem occurs when trying to resolve resources matching the pattern: "
+ classSearchPattern, e);
}
MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
for (Resource resource : resources) {
try {
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
if (typeFilter.match(metadataReader, metadataReaderFactory)) {
String className = metadataReader.getClassMetadata().getClassName();
Class<?> annotatedClass = classLoader.loadClass(className);
// CHECK IF THE CLASS HAS PROPERLY ANNOTATED FIELDS AND
// DO SOMETHING WITH THE CLASS FOUND... E.G., PUT IT IN SOME REGISTRY
}
} catch (Exception e) {
throw new FindException("Failed to analyze annotation for resource: " + resource, e);
}
}
}
Related
I have an instance of class android.icu.util.TimeZone which actually instance of android.icu.impl.OlsonTimeZone. I need to retrieve a field of transitions using reflection. But getDeclaredFields retrieves only one static field. How could it be, if during debuging I see lots of fields in this class?
TimeZone tz = TimeZone.getTimeZone("Europe/Kiev");
try {
Class<?> actionClass = Class.forName(tz.getClass().getName()/*, true, ClassLoader.getSystemClassLoader()*/); // Also have tried with SystemClassLoader
Field[] allFields = actionClass.getDeclaredFields();
for (Field field : allFields) {
Log.d("field:", field.getName());
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
When I try to retrieve transitionTimes64 directly I'v got NoSuchFieldException No field transitionTimes in class Landroid/icu/impl/OlsonTimeZone; (declaration of 'android.icu.impl.OlsonTimeZone' appears in /apex/com.android.runtime/javalib/core-libart.jar
I would like to write a method that returned the value of the annotation method.
I tried to use this variants, nothing succeeded
Params:
clazz - Сlass that has annotations
annotationClazz - My Annotation.class
parametersName - method`s name
This is my code:
public static Object getAnnotationValue(Class clazz, Class annotationClazz, String parametersName) {
Annotation an = clazz.getAnnotation(annotationClazz);
if (an.equals(null)) {
throw new CoreError("Класс " + clazz + " не содержит аннотацию " + annotationClazz);
}
PageName pn = (PageName) an;
try {
//its working!
System.out.println(pn.value());
//not working :(
System.out.println(an.getClass().getMethod(parametersName).getDefaultValue()); //not working :(
System.out.println(an.annotationType().getDeclaredMethod(parametersName, annotationClazz).getDefaultValue());
System.out.println(pn.getClass().getMethod(parametersName).getDefaultValue());
System.out.println(pn.annotationType().getDeclaredMethod(parametersName, annotationClazz).getDefaultValue());
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
Is it even possible?
Your code keeps looking for the default value, but your question never mentions if the default value exists. To get the provided value, you must invoke the method on an instance.
Besides, you're using getMethod and getDeclaredMethod wrong in most cases.
Here's a working example:
public static Object getAnnotationValue(Class clazz, Class annotationClazz, String parameterName) {
Annotation an = clazz.getAnnotation(annotationClazz);
System.out.println(an.annotationType().getMethod(parameterName).invoke(an));
}
So for a class like:
#PageName("testPage") //Same as #PageName(value = "testPage")
public class Example {}
calling
getAnnotationValue(Example.class, PageName.class, "value")
would print
testPage
I am trying to get the name of variable in android using java.
The variable has a annotation, and I want to get the variable's name with the annotation's name. is this possible?
just like this,
#getnameofthisfield
private String name;
use getnameofthisfield and get name
You can do it like this:
Class<YourClass> clazz = // somehow get a reference to the class that contains the field
Field[] fields = clazz.getDeclaredFields();
List<String> fieldNames = new LinkedList<>();
for (Field field : fields) {
if (field.isAnnotationPresent(#getnameofthisfield.class)) {
fieldNames.add(field.getName);
}
}
In the end fieldNames will contain the names of all fields, annotated with #getnameofthisfield.
This comes up when you have a Data holder class that is a model for Firebase fields (for example) and the spelling of the member names must exactly equal the Strings in the Firebase tree. While I have not eliminated the duplicate typing/spelling of the Strings/fields, this will at least detect these programming errors at run-time.
public class User {
private String email;
private String name;
// avoid out-of-sync String names of fields in other files
public static String getFieldName(String fieldRequest) {
try {
return User.class.getDeclaredField(fieldRequest).getName();
} catch (NoSuchFieldException e1) {
e1.printStackTrace();
throw new RuntimeException("Unrecognized field in "
+ User.class.getSimpleName() + ", (" + fieldRequest + ")"); }
}
Here is an example usage:
// demonstration of how the getFieldName() protects against mistakes...
String userNameField = User.getFieldName("name"); // this works
String userEmailField = User.getFieldName("userEmail"); // this throws an error
Get annotation value
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
public class Util{
#SuppressWarnings("unchecked")
public static<T> T getAnnotationValue(Class<?> clazz,Class<? extends Annotation> annotationClass,String element) throws Exception {
Annotation annotation = clazz.getAnnotation(annotationClass);
Method method = annotationClass.getMethod(element,(Class[])null);
if (annotation == null)
return((T)method.getDefaultValue());
return((T)method.invoke(annotation,(Object[])null));
}
}
In my understanding that isnt possible, the java compiler doesn't save variable names. What is it that your trying to do with such name?
How can I iterate over the attributes of an object, with the attribute names provided in a list/array - NOT all attributes, like using reflection & getDeclaredFields().
public class MyClass
{
public type1 att1;
public type2 att2;
public type3 att3;
public MyClass(
att1="helo";
att2="bye";
att3="morning";
);
...
public void function()
{
String myStrings[];
myStrings = new String[] { "att2", "att3" };
MyClass myobject = new MyClass();
for(var in myStrings)
{
System.out.println(var);
System.out.println(myobject.var);
System.out.println();
}
}
}
Your question is somewhat ambiguous about using reflection. If you are OK with reflection, but want specific fields only without iterating over getDeclaredFields(), then the following code should work for you:
for (String var : myStrings) {
Field field = MyClass.class.getDeclaredField(var);
field.setAccessible(true);
System.out.println(var);
System.out.println(field.get(myObject));
System.out.println();
}
Note that this code works for private fields, too. Also, keep in mind that you'll have to handle exception associated with the reflection calls.
UPDATE: Exceptions thrown in this code.
MyClass.class.getDeclaredField(var) declares a checked NoSuchFieldException. You must handle it because obviously there is no mechanism to make sure that the fields in myString match an actual implementation of MyClass.
field.get(myObject) throws a checked IllegalAccessException if the field is inaccessible. Which it should not be because of field.setAccessible(true), but you still have to catch or re-throw the exception.
There are also unchecked exceptions you may want to handle. See the javadoc for details
java.lang.Class.getDeclaredField(String)
java.lang.reflect.AccessibleObject.setAccessible(boolean) inherited by java.lang.reflect.Field
java.lang.reflect.Field.get(Object)
You probably want to use some technology that builds on top of JavaBeans / BeanInfo. Apache Commons / BeanUtils is a good starting point here.
Please refer to this previous answer of mine for more info:
https://stackoverflow.com/a/5856982/342852
But if you just want to use fields, not bean properties, here's a Java 8 method to do so:
public static Map<String, Object> getFieldProperties(Object o, Collection<String> fields) {
Class<?> type = o.getClass();
return fields.stream().map(n -> {
try {
return type.getDeclaredField(n);
} catch (NoSuchFieldException e) {
throw new IllegalStateException(e);
}
}).collect(Collectors
.toMap(
(Function<Field, String>) Field::getName,
(Function<Field, Object>) field -> {
try {
field.setAccessible(true);
return field.get(o);
} catch (IllegalAccessException e) {
throw new IllegalStateException(e);
}
}));
}
Unfortunately the checked exceptions make this more verbose than it would need to be.
Is there such a functionality in JAXB to perform operations on a class after it is unmarshalled i.e. after it is constructed by JAXB? If not, how could I achieve this?
You can use JAXB Unmarshal Event Callbacks which are defined in your JAXB class e.g:
// This method is called after all the properties (except IDREF) are unmarshalled for this object,
// but before this object is set to the parent object.
void afterUnmarshal( Unmarshaller u, Object parent )
{
System.out.println( "After unmarshal: " + this.state );
}
Though the the demanded functionality seems not to be present in JAXB, I managed to
achieve something which goes into the right direction:
I'm using JSR-305's #PostConstruct annotation
(it's just a nacked annotation, no functionality is provided by the JSR)
I add an unmasrshaller-listener to the unmarshaller, which gets invoked by JAXB every time an object was unmarshalled.
I inspect this object using Java reflection and search for the #PostConstruct annotation on a method
I execute the method
Tested. Works.
Here is the code. Sorry, I'm using some external reflection API to get all methods, but I think the idea is understandable:
Implementation
JAXBContext context = // create the context with desired classes
Unmarshaller unmarshaller = context.createUnmarshaller();
unmarshaller.setListener(new Unmarshaller.Listener() {
#Override
public void afterUnmarshal(Object object, Object arg1) {
System.out.println("unmarshalling finished on: " + object);
Class<?> type = object.getClass();
Method postConstructMethod = null;
for (Method m : ReflectionUtils.getAllMethods(type)) {
if (m.getAnnotation(PostConstruct.class) != null) {
if (postConstructMethod != null) {
throw new IllegalStateException(
"#PostConstruct used multiple times");
}
postConstructMethod = m;
}
}
if (postConstructMethod != null) {
System.out.println("invoking post construct: "
+ postConstructMethod.getName() + "()");
if (!Modifier.isFinal(postConstructMethod.getModifiers())) {
throw new IllegalArgumentException("post construct method ["
+ postConstructMethod.getName() + "] must be final");
}
try {
postConstructMethod.setAccessible(true); // thanks to skaffman
postConstructMethod.invoke(object);
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
} catch (InvocationTargetException ex) {
throw new RuntimeException(ex);
}
}
}
});
EDIT
Added a check for #PostConstruct-annotated method, to ensure it is final.
Do you think it's a useful restriction?
Usage
Here is how the concept might be used.
#XmlAccessorType(XmlAccessType.NONE)
public abstract class AbstractKeywordWithProps
extends KeywordCommand {
#XmlAnyElement
protected final List<Element> allElements = new LinkedList<Element>();
public AbstractKeywordWithProps() {
}
#PostConstruct
public final void postConstruct() {
// now, that "allElements" were successfully initialized,
// do something very important with them ;)
}
}
// further classes can be derived from this one. postConstruct still works!
Filed a feature request
https://jaxb.dev.java.net/issues/show_bug.cgi?id=698
It's not a 100% solution, but you can always register a XmlAdapter using #XmlJavaTypeAdapter annotation
for this type.
The downside would be that you have to serialize the class yourself (?). I am not aware of any simple way of accessing and calling the default serialization mechanism. But with custom [XmlAdapter] you can control how is the type serialized and what happens before/after it.