custom annotations for method in java - java

I am new to annotations in java, I want to have an annotation on method to do some stuff for me like:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface LogActivity {
String logMessage() default "default message";
}
I want to have some methods in different classes like:
public class A {
#LogActivity(logMessage = "called foo() in class A")
public void foo() {
// some code
}
}
and
public class B {
#LogActivity(logMessage = "called foo() in class B")
public void foo() {// some code}
#LogActivity(logMessage = "called foo1() in class B")
public void foo1() {// some code}
}
I need a method which will print these logMessages on the screen.
I just need help writing the method which will be executed after the call to these foo and foo1 goes but before their execution starts.
Blockquote I need this annotation in any number of classes in my project so I cannot prefer to do something like:
Method [] methods = Class.forName(theObject.getClass().getName()).getMethods();
and
LogActivity logActivity = methods[i].getAnnotation(LogActivity.class);
I googled some things but didn't really understand the solution.
Thank you in advance.

Related

Effects of java super class call

I'm new to Java and I'm having problems with some OOP, mostly inheritance, concepts.
Consider these two classes:
public class Foo() {
protected String rawData;
public String getSomething(String rawData) {
// ...
this.rawData = rawData;
prepareData();
return rawData;
}
protected void prepareData() {
// do something with class rawData
}
}
public class Bar() extends Foo {
#Override
public String getSomething(String rawData) {
// ...
return super.rawData;
}
#Override
protected void prepareData() {
// do something with class rawData too
}
}
Calling Bar class getSomething() method will lead me to a call of Foo class prepareData()?
Only if your override calls the base method.
Other than base class constructors, Java does not silently call methods for you.
Java always goes deeper even without #Override.
If you don't override the base method it will run it.
If you are in Bar and you want to run Foo method, you can use super.prepareData() in Bar - It will be use when you want to run the super method and add something to it.

Can I remove a method from a class instance in java?

Lets say I have a class called 'Foo', with some methods:
public class Foo{
public void a(){
//stuff
}
public void b(){
//stuff
}
}
And i have an instance of Foo:
Foo instanceOfFoo = new Foo();
Can i remove the method 'a' from 'instanceOfFoo'?
You can't remove a method, not without changing the byte code and breaking the code's "contract", but you could extend the class and have the child class's method override throw an UnsupportedOperationException if called. Also the child class should deprecate the method, and explain in its javadoc the rationale behind it, and what to use in its place.
This would change the class's contract, but in a more responsible way then say fiddling with the byte code.
For example:
public class Foo {
public void a() {
// stuff
}
public void b() {
// stuff
}
}
public class FooChild extends Foo {
/**
* #deprecated: This method should no longer be used and will throw an exception
*/
#Override
#Deprecated
public void a() {
String text = "The method a is no longer supported";
throw new UnsupportedOperationException(text);
}
}
Short answer: No, not really.
Long answer: If you can control the ClassLoader being used to load the Foo class, you can intercept the request to load the Foo class and use ASM or Javassist to modify the class's bytecode before loading it.

Call super.super.method, skipping super.method

I have the following (third-party) class structure. We'll call the third-party project ProjectSeriously, and note that I'm using System.out.println in place of other complicated functionality (100s of lines of code).
class A {
public void hi() {
// Do an important thing
System.out.println("Important thing A");
}
}
class B extends A {
public void hi() {
// Do some terrible, terrible things
System.out.println("TERRIBLE THING B");
// Do that important thing
super.hi();
}
}
Now I want to write this (this isn't valid java):
class C extends B {
public void hi() {
// Do some not-so-terrible things
System.out.println("Ok thing C");
// Do that important thing
super.super.hi();
}
}
I have to pass an instanceof B to some other piece of this wonderful project, ProjectSeriously. Seeing as these are public methods, I feel like this should be possible.
You could use javassist to modify the class before any use of it.
But this is a really ugly hack, please try to refactor the code in A and/or B the expose the important parts.
package test;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.CtNewMethod;
class A {
public void hi() {
// Do an important thing
System.out.println("Important thing A");
}
}
class B extends A {
public void hi() {
// Do some terrible, terrible things
System.out.println("TERRIBLE THING B");
// Do that important thing
super.hi();
}
}
class C extends B {
public void hi() {
// Do some not-so-terrible things
System.out.println("Ok thing C");
// Do that important thing
super.hi();
}
}
public class Main {
public static void main(String[] args) throws Exception {
CtClass cc = ClassPool.getDefault().get("test.B"); // don't use test.B.class.getName() as this force the class loader to load the class
CtMethod m1 = cc.getDeclaredMethod("hi");
cc.removeMethod(m1);
CtMethod m2 = CtNewMethod.copy(m1, cc, null);
m2.setBody("{ /* override method B.hi() body */ return super.hi();}", "this", m1.getName());
cc.addMethod(m2);
cc.toClass();
C obj = new C();
obj.hi();
}
}
Result:
Ok thing C
Important thing A
Unless you explicitly expose the method(s), which sort-of goes against the design pattern, there aren't many other options:
public class GrandParent {
public void hi() {
hiGrandParent();
}
protected final void hiGrandParent() {
System.out.println("Hi from grandparent.");
}
public static class Parent extends GrandParent {
#Override
public void hi() {
hiParent();
}
protected final void hiParent() {
System.out.println("Hi from parent.");
}
}
public static class Child extends Parent {
#Override
public void hi() {
hiChild();
super.hi();
hiParent();
hiGrandParent();
}
protected final void hiChild() {
System.out.println("Hi from child.");
}
}
}
Run with:
public final class RunIt {
public static void main(final String[] args) {
new GrandParent.Child().hi();
}
}
Expected output:
Hi from child.
Hi from parent.
Hi from parent.
Hi from grandparent.
This would break encapsulation in a terrible way (you'd essentially be disabling some part of class B's logic), and it shouldn't be possible in Java. I'm pretty sure it isn't possible.
Yeah its not really possible in a "standard" java way, also its a bad design decision but OP might not have access to the original class. I've faced this problem several times earlier with different jars.
If you want to skip for example a private method call in one of the super classes, but still need the other parts of the constructor code or the functionality of the superclasses, the only "easy" way to do this is to basically copy-paste that part of the code into your own class. For example if you have these classes:
public class Foo {
public Foo() {
importantFunctionality();
}
private void importantFunctionality() {
System.out.println("DOING IMPORTANT STUFF");
}
}
public class Bar extends Foo {
public Bar() {
super(); //constructor gets called
killAllBabies(); //I dont want this to get called, but its a private method meaning no overriding
solveWorldHunger(); //I want to call this, but this is a private method, so no calling this from child classes
}
private void killAllBabies() {
System.out.println("KILLING ALL BABIES");
}
private void solveWorldHunger() {
System.out.println("SOLVING WORLD HUNGER");
}
}
public class MyClass extends Bar {
public MyClass() {
super(); //Not good, because stuff I dont want gets called here
}
}
Only way to solve this is to "skip" the previous class and extend the original class and implement the functionality of the skipped class. Unfortunately this was an issue for us with a certain framework because of bad extendibility:
public class MyClass extends Foo {
public MyClass() {
super();
solveWorldHunger();
}
private void solveWorldHunger() {
System.out.println("SOLVING WORLD HUNGER");
}
}

How do you extend a Java class and change annotations?

I have one Java class that uses annotations. I want to write a version that extends it and changes the annotations on existing methods.
So there will be a method that has:
#myAnnotation(value=VALUE_THAT_CHANGE_IN_SUBCLASS)
myMethod(){
}
The subclass will have a couple new methods, but will mostly just change annotations in the manner I said.
Though I'm not sure why you'd want to, you'd need to extend the class, override the methods, and apply the annotations:
public class App
{
public static void main(String[] args) throws NoSuchMethodException
{
Class<MyClass> c = MyClass.class;
MyAnnotation a = c.getMethod("someMethod",null).getAnnotation(MyAnnotation.class);
System.out.println(a.name());
Class<MySubclass> c2 = MySubclass.class;
a = c2.getMethod("someMethod",null).getAnnotation(MyAnnotation.class);
System.out.println(a.name());
}
}
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
#interface MyAnnotation {
String name() default "";
}
class MyClass {
#MyAnnotation(name="Some value")
public String someMethod() {
return "Hi!";
}
}
class MySubclass extends MyClass {
#Override
#MyAnnotation(name="Some other value")
public String someMethod() {
return super.someMethod();
}
}
Output:
Some value
Some other value

Java reflection derived class

This is my scenario "I have a abstract class. There are many derived classed extending this abstract class with the use of annotations. In addition, I have a method of abstract class, that was reflected all notations in one particular derived class".
// Here's a definition of annotation
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface SampleAnnotation {
int sample();
}
public abstract class A {
// Here's a method to reflect all annotations
// in particular derived class like B or C
#Override
public void foo() {
}}
public class B extends A {
#SampleAnnotation (sample = 1)
public void step1() {}
#SampleAnnotation (sample = 2)
public void step2() {}
}
public class C extends A {
#SampleAnnotation (sample = 1)
public void step1() {}
#Sample (stage = 2)
public void step2() {}
}
How can I use java reflection to reflect all the annotations in specific derived class like B or C ?
Perhaps what you have in mind is this Reflections library.
Using Reflections you can query your metadata such as:
get all subtypes of some type
get all types/methods/fields annotated with some annotation, w/o annotation parameters matching
get all resources matching matching a regular expression
It depends:
Do you want to get all method annotations of a concrete class
Do you want to get all method annotations of all concrete classes
The first one can be achieved with a method implementation of foo like this:
public void foo() {
for (Method method : this.getClass().getDeclaredMethods()) {
for (Annotation a : method.getAnnotations()) {
// do something with a
}
}
}
Then you can invoke foo from your concrete class, for instance:
new B().foo();
For the second case you will need to do class path scanning as Peter Lawrey has pointed out.

Categories

Resources