#Service
public class TestService{
#DynamicReference
private ITestProvider testProvider;
public void run() {
}
}
DynamicReference dynamicRefrence = filed.getAnnotation(DynamicReference.class);
-->NOT NULL
This code is fine in this case. But when I add #Transactional in method run, then #DynamicReference will lose
#Service
public class TestService{
#DynamicReference
private ITestProvider testProvider;
#Transactional
public void run() {
}
}
DynamicReference dynamicRefrence = filed.getAnnotation(DynamicReference.class);
-->NULL
How can I get field annotation #DynamicReference in cglib proxy class?
this is get Field code:
Object o = this.applicationContext.getBean(beanName);
Class<?> clazz = o.getClass();
for (Field filed : clazz.getDeclaredFields()) {
DynamicReference dynamicRefrence = filed.getAnnotation(DynamicReference.class);
}
From Class.getDeclaredFields():
Returns an array of Field objects reflecting all the fieldsdeclared by the class or interface represented by this Class object. This includes public, protected, default(package) access, and private fields, but excludes inherited fields.
In your case, once you have a subclass-based proxy from cglib, the field will only exist in the superclass. Depending on your use case, you might want to collect all fields up in the inheritance chain that have you custom annotation.
Example code:
Collection<Field> fieldsWithAnnotation = new ArrayList<>();
Class<?> clazz = // your class
while(clazz != null) {
for (Field field : clazz.getDeclaredFields()) {
DynamicReference dynamicRefrence = field.getAnnotation(DynamicReference.class);
if(dynamicRefrence != null)
fieldsWithAnnotation.add(field);
}
clazz = clazz.getSuperclass();
}
EDIT: This approach works to find the annotated field. However, doing field.set(proxyInstance, value) will actually set the field in the proxy. This does not help you, as even though the proxy subclasses, it still uses delegation to forward method calls to a wrapped instance of your actual class. Since your goal is apparently to set the field in this wrapped instance, I would advise you to not use a custom field injection but rather setter injection. Your code would look roughly like this (untested):
// in TestService
private ITestProvider testProvider;
#DynamicReference
public void setTestProvider(ITestProvider testProvider) { ... }
// Getting the method
while(clazz != null) {
for (Method method : clazz.getDeclaredMethods()) {
DynamicReference dynamicRefrence = method.getAnnotation(DynamicReference.class);
if(dynamicRefrence != null)
methodsWithAnnotation.add(method);
}
clazz = clazz.getSuperclass();
}
// invoking it
method.invoke(proxyInstance, dependencyInstanceYouWantToSet);
The proxy should delegate the method call to your wrapped instance. Maybe you even want to make the method protected.
The alternative would be getting the callback-field of the proxy and setting the field on that instance, but the approach above seems much cleaner (some might say that magic field injection is evil and you should always use setter/constructor injection for a clean oop approach).
Edit 2: maybe you could also rethink if you want to actually reinvent the DI framework and leverage the underlying existing DI framework functionality. Using #Qualifier or some custom injection resolver comes to mind. See eg this tutorial
Related
Imagine an annotation called "MyAnn" with runtime retention, a class MyClass, and an abstract class called MyData. MyClass has a field of type MyData, annotated with MyAnn. Within the instance of MyData, how do see if the annotation MyAnn is present and retrieve its information?
Note - in Java8 I know we can directly annotate the inner class at construction - and that works - but I need this working based on the field annotation.
Thanks for any help!
public MyClass extends MySuperClass() {
#MyAnn(value = "something")
protected MyData mydata;
public void doSomething() {
mydata = new MyData() {};
mydata.initialize();
}
}
public abstract MyData() {
String myValue = null;
public void initialize() {
if (***I am annotated with MyAnn) {
myValue = (***value from annotation MyAnn);
}
}
}
#Retention(RetentionPolicy.RUNTIME)
public #interface MyAnn {
String myvalue;
}
MyData cannot directly know whether it has been annotated with MyAnn, because it has no knowledge of whether the current instance is a field or a standalone instance, and if it is a field, then whether the field has or has not been annotated with MyAnn.
So, you will need to somehow obtain and pass the value to initialize(), and you will need to somehow obtain the value at the place where initialize() is called. And from your code, it appears that "something" can be passed as a parameter to initialize(), making the whole thing a lot easier than annotating the field and then checking whether the field is annotated.
But in any case, if you want to check whether a field is annotated, you have to:
obtain the fields of your class with getClass().getDeclaredFields()
loop over the fields; for each field, either
invoke isAnnotationPresent( MyAnn.class ) or
invoke field.getAnnotations(), loop for each annotation, and check whether this annotation instanceof MyAnn.class
Once you have found the annotation, you can get its value with annotation.value();
I want to look for a specific annotation of every method in a class and if a method with that annotation is found, i would like to invoke it.
Also, if it's not found in the current class, a check on all inheriting classes should be made.
My problem is that there might be some methods that are protected, private etc. and I would like to ignore those modifiers and to gain access to all methods (i.e even if it's private etc.)
So this is how I invoke (given is the name of the annotation that I'm looking for:
if (m.isAnnotationPresent(Given.class)) {
m.invoke(instObj, intArgument);
}
(And this is how I check the rest of the class hierarchy - if i made a mistake somewhere, enlighten me please:
Class<?> superC = c.getSuperclass();
while (!(superC.equals(Object.class))) {
handleGiven(instObj, superC, methods, currentSentence,
methodArgument);
when handleGiven is a recursive call.
You need to use getDeclaredMethods to get all the methods (public, protected, etc), like this:
public Method findMethodWithAnnotation(Class<?> clazz,
Class<? extends Annotation> annotation) {
for (Method m : clazz.getDeclaredMethods()) {
if (m.isAnnotationPresent(annotation)) {
return m;
}
}
return null;
}
And check like this:
Class<?> clazz = ..; //get the class
Method m = null;
do {
m = findMethodWithAnnotation(clazz, DesiredAnnotation.class);
clazz = clazz.getSuperclass();
} while (m == null && clazz != null);
System.out.println(m);
Also make sure that your annotation has the following annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
If you need the annotation for fields, check the getDeclaredFields, and similars methods.
You need to make the method accessible, before the invocation
m.setAccessible(true);
If you want a more compact and recursive implementation, you can change to:
public Method findMethodWithAnnotation(Class<?> clazz,
Class<? extends Annotation> annotation) {
if (clazz == Object.class || clazz == null) return null;
for (Method m : clazz.getDeclaredMethods()) {
if (m.isAnnotationPresent(annotation)) {
return m;
}
}
return findMethodWithAnnotation(clazz.getSuperClass(), annotation);
}
And the use is:
Method m = findMethodWithAnnotation(clazz, DesiredAnnotation.class)
if (m == null) log("Nor the class, or any superclass have the desired annotation")
else {
m.setAccessitble(true);
m.invoke(obj, arguments);
}
Considerations:
this don't cover interfaces, if you need to cover interfaces, check getInterfaces() (this method return the interfaces in the order of declaration).
If a a class A has a override method desiredMethod, with no annotation, and extends a class SuperA, witch has a method desiredMethod, with the desired annotation, this return SuperA#desiredMethod, but when you invoke it, it will invoke in the A class (like a normal invocation)
My problem is that there might be some methods that are protected, private etc. and I would like to ignore those modifiers and to gain access to all methods (i.e even if it's private etc.)
You need to call Method.setAccessible(true) before invoking it, not forgetting to restore its original value afterwards, in a finally block.
I am developing a framework which allows developers to do database operations through service layer. Service classes will send the database request dto object which will be annotated with sql ID to use as ID in MyBatis. Later I will read the annotation value by reflection.
First of all, I created a custom annotation interface.
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface MyBatisMapper {
String namespace() default "";
String sqlId() default "";
}
And interface for database request dto object.
public interface IReqDto {
public String getDaoType();
}
And database request dto object which will implement the above IReqDto interface.
#MyBatisMapper(namespace="User", sqlId="userInsert")
public class UserInsertReqDto implements IReqDto{
//beans and getters/setters
}
The above bean may vary as requirement of the developer. This is not part of the framework. Developer must implement IReqDto interface in any kind of database request object he use.
What I am trying is to read the annotated values (namespace and sqlId) from database invoker class by using reflection.
I understand that I can get the annotated value by doing this.
Class<UserInsertReqDto> ReqDto = UserInsertReqDto.class;
for(Annotation annotation : ReqDto.getAnnotations()) {
System.out.println(annotation.toString());
}
But my problem is, as the UserInsertReqDto will vary, I tried to use reflection to IReqDto interface.
Class<IReqDto> ReqDto = IReqDto.class;
Well, surely it doesn't work.
The question is - how can I read the annotated value from database request object in this situation? Thanks.
Maybe I'm still misunderstanding your question, so correct me if necessary.
You will be given an object of a custom implementation of ReqDto
ReqDto object = ...; // get instance
Class<?> clazz = object.getClass(); get actual type of the instance
for(Annotation annotation : clazz.getAnnotations()) { // these are class annotations
System.out.println(annotation.toString());
}
or
MyBatisMapper mapperAnnotation = clazz.getAnnotation(MyBatisMapper.class);
if (mapperAnnotation != null) {
System.out.println(mapperAnnotation.namespace()
System.out.println(mapperAnnotation.sqlId()
}
Reflection works regardless of the type. So, instead of referring to the concrete class, simply use Object#getClass() and/or Class<?>. E.g.
public Metadata getMetadata(Object pojo) {
Annotation annotation = pojo.getAnnotation(MyBatisMapper.class);
if (annotation == null) {
return null;
}
return new Metadata(annotation.getNamespcae(), annotation.getSqlId());
}
where Metadata is just a value class that you can use later on that contains the values about the object. You can also directly work with the MyBatisWrapper annotation.
I am using Scannotation to scan classfiles and get all classes with annotations present on any element of that class. Using reflection i've been able to find out all annotations on parameters in methods, but i need objects of those annotations so i can later get its parameters (or what do you call it).
this is fraction of my code, which will return annotations i want, but i can't work with them.
public Set<Class> getParametersAnnotatedBy(Class<? extends Annotation> annotation) {
for (String s : annotated) {
//annotated is set containing names of annotated classes
clazz = Class.forName(s);
for (Method m : clazz.getDeclaredMethods()) {
int i = 0;
Class[] params = m.getParameterTypes();
for (Annotation[] ann : m.getParameterAnnotations()) {
for (Annotation a : ann) {
if (annotation.getClass().isInstance(a.getClass())) {
parameters.add(a.getClass());
//here i add annotation to a set
}
}
}
}
}
}
i know i can work with it, if i know the annotation, like this:
#Retention(RetentionPolicy.RUNTIME)
public #interface MyAnnotation {
public String name();
public int count();
}
// ... some code to get annotations
MyAnnotation ann = (MyAnnotation) someAnnotation;
System.out.println(ann.name());
System.out.println(ann.count());
but so far i was not able to do it this way, using reflection... I would very much appreciate any directions, thanks in advance.
PS.: is there any way to get object of parameters like Field for fields, Method for methods etc. ?
You need to use a.annotationType. When you call getClass on an annotation you are actually getting its Proxy Class. To get the real class that it is you need to call annotationType instead of getClass.
if (annotation.getClass() == a.annotationType()) {
parameters.add(a.annotationType());
// here i add annotation to a set
}
Is there any way to tell an ObjectOutputStream which fields of a serializable class should be serialized without using the keyword transient and without defining an serialPersistentFields-array?
Background: I need to use annotations to define which members of a class should be serialized (or better: not be serialized). The involved classes must implement the interface Serializable, but NOT Externalizable, so I don't want to implement the serialization/deserialization algorithm for each object but rather just use annotations for it. I can not use the transient keyword, because the annotation requires some further checks to determine whether a field should be serialized or not. These checks have to be done by the ObjectOutputStream (or in my own subclass of ObjectOutputStream). I also cannot define a serialPersistentFields-array in each class, because as explained previously, at compilation time it is not defined which fields should be serialized.
So the only thing that should be notet in the affected class is the annotation at field-level (#Target(ElementType.FIELD)).
I've tried quite a lot of approaches in the last few days, but haven't found one which is working:
The ObjectOutputStream has a method writeObjectOverride(Object) which can be used to define an own implementation of the serialization-process when extending ObjectOutputStream. This only works if the ObjectOutputStream is initialized with the no-argument-constructor because otherwise writeObjectOverride is never invoked. But this approach requires me to implement the whole serialization-process by myself and I don't want to do this, as it is quite complex and already implemented by the default ObjectOutputStream. I am looking for a way to just modify the default serialization implementation.
Another approach was extending ObjectOutputStream again and overriding writeObjectOverride(Object) (after calling enableReplaceObject(true)). In this method, I tried using some kind of SerializationProxy (see What is the Serialization Proxy Pattern?) to encapsulate the serialized object in a proxy which defines a List of Fields which should be serialized. But this approach also fails as writeObjectOverride then is also called for the List of fields (List<SerializedField> fields) in the Proxy resulting in an infinite loop.
Example:
public class AnnotationAwareObjectOutputStream extends ObjectOutputStream {
public AnnotationAwareObjectOutputStream(OutputStream out)
throws IOException {
super(out);
enableReplaceObject(true);
}
#Override
protected Object replaceObject(Object obj) throws IOException {
try {
return new SerializableProxy(obj);
} catch (Exception e) {
return new IOException(e);
}
}
private class SerializableProxy implements Serializable {
private Class<?> clazz;
private List<SerializedField> fields = new LinkedList<SerializedField>();
private SerializableProxy(Object obj) throws IllegalArgumentException,
IllegalAccessException {
clazz = obj.getClass();
for (Field field : getInheritedFields(obj.getClass())) {
// add all fields which don't have an DontSerialize-Annotation
if (!field.isAnnotationPresent(DontSerialize.class))
fields.add(new SerializedField(field.getType(), field
.get(obj)));
}
}
public Object readResolve() {
// TODO: reconstruct object of type clazz and set fields using
// reflection
return null;
}
}
private class SerializedField {
private Class<?> type;
private Object value;
public SerializedField(Class<?> type, Object value) {
this.type = type;
this.value = value;
}
}
/** return all fields including superclass-fields */
public static List<Field> getInheritedFields(Class<?> type) {
List<Field> fields = new ArrayList<Field>();
for (Class<?> c = type; c != null; c = c.getSuperclass()) {
fields.addAll(Arrays.asList(c.getDeclaredFields()));
}
return fields;
}
}
// I just use the annotation DontSerialize in this example for simlicity.
// Later on I want to parametrize the annotation and do some further checks
#Target(ElementType.FIELD)
#Retention(RetentionPolicy.RUNTIME)
public #interface DontSerialize {
}
When I found out that it is possible to modify modifiers at runtime (see Change private static final field using Java reflection) I tried to set the transient-Modifier at runtime if the corresponding annotation was set.
Unfortunately this also does not work, because the approach used in the previous link seems to work only on static fields.
When trying it with non-static fields it runs without an exception but is not persisted because is looks like Field.class.getDeclaredField(...) returns new instances of the affected fields every time it is called:
public void setTransientTest() throws SecurityException,
NoSuchFieldException, IllegalArgumentException,
IllegalAccessException {
Class<MyClass> clazz = MyClass.class;
// anyField is defined as "private String anyField"
Field field = clazz.getDeclaredField("anyField");
System.out.println("1. is "
+ (Modifier.isTransient(field.getModifiers()) ? "" : "NOT ")
+ "transient");
Field modifiersField = Field.class.getDeclaredField("modifiers");
boolean wasAccessible = modifiersField.isAccessible();
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() | Modifier.TRANSIENT);
modifiersField.setAccessible(wasAccessible);
System.out.println("2. is "
+ (Modifier.isTransient(field.getModifiers()) ? "" : "NOT ")
+ "transient");
Field field2 = clazz.getDeclaredField("anyField");
System.out.println("3. is "
+ (Modifier.isTransient(field2.getModifiers()) ? "" : "NOT ")
+ "transient");
}
The output is:
1. is NOT transient
2. is transient
3. is NOT transient
So after calling getDeclaredField again (Field field2 = clazz.getDeclaredField("anyField");) it already lost the transient modifier.
Next approach:
Extend ObjectOutputStream and override ObjectOutputStream.PutField putFields() and define an own PutField-implementation. PutField lets you specify which (additional) fields are serialized but unfortunately the interface only has a lot of methodes of the form put(String name, <type> val) and when implementing these I cannot associate the method calls with the class field it is invoked from. For instance when serializing a field declared as private String test = "foo" the method put("test", "foo") is invoked, but I cannot associate the value of name (which is test) with the class containing the field test because no reference to the containing class is available and therefore it is impossible to read the annotation noted for the field test.
I also tried a few other approaches but as already mentioned I was not able to successfully serialize all fields except the ones with the annotation DontSerialize present.
One thing I also came across were ByteCode manipulators. Maybe it is possible with these but I have a requirement for not using any external tools - it needs to be pure Java (1.5 or 1.6).
Sorry for this really long post but I just wanted to show what I already tried and am hoping that someone can help me.
Thanks in advance.
I would reconsider if "Serialization" is really the thing you want to do. Given that the Serialization rules depends on some logic defined at runtime, the Deserialization process will be a nightmare to write.
Interesting problem, though.
Without rewriting much of Java Serialization, you will need to rewrite the bytecode. At runtime this can be done with Java Agents, but can also be done to class files during the build.