I'm trying to spot, using reflection, the 'init' method that is annotaded with the #Override annotation (or with whatever annotation), but ok, heres my example, much simplified, ofcourse
Base class:
public abstract class A
{
public void init()
{
}
}
Then here the subclass:
public class B extends A
{
String bla;
#Override
public void init()
{
}
public void init(String bla)
{
this.bla=bla;
}
}
So the code i run to get the annotated method is this:
public static void main(String[] args)
{
ClassLoader c = Main.class.getClassLoader();
try
{
Class<?> clazz = c.loadClass("correct.path.to.class.B");
for (Method method : clazz.getDeclaredMethods())
{
if (method.getName().equals("init"))
{
System.out.println(method.getDeclaredAnnotations().length);
}
}
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
}
Both methods are correctly found but surprisingly, i get '0' twice when reading the length of the arrays containing the annotations, any idea whats wrong here?
The method getAnnotation() gives me the same results
Check the documentation for #Override and RetentionPolicy. Basically, the #Override annotation is not available at runtime, it's a source only annotation.
http://docs.oracle.com/javase/7/docs/api/java/lang/annotation/RetentionPolicy.html
http://docs.oracle.com/javase/7/docs/api/java/lang/Override.html
Related
I want to have a class to run other classes in java, like constructor parameterized with a class to run that class later on, similar to this
class MyClass{
Class classToRun;
public MyClass(Class c) {
super();
this.classToRun = c;
}
public void runClass(){
classToRun.someStaticMethod();
}
}
where classToRun possible classes doesn't have a common ancestor, but all have method someStaticMethod, and have no idea about MyClass, which runs them.
But there are problems, like inner classes cannot have static methods, classes cannot be cast Class, etc.
There are solutions for parameterized with class methods, like
How do I pass a class as a parameter in Java?
Passing a class as an argument to a method in java
but not for constructors.
What is the proper solution to do this?
Use lambdas and pass the method reference: they match on the method signature. For void someStaticMethod() you can use Runnable.
class MyClass{
private final Runnable methodToRun;
public MyClass(Runnable someStaticMethod) {
methodToRun = someStaticMethod;
}
public void runClass(){
methodToRun.run();
}
}
new MyClass(SomeClass::someStaticMethod).runClass();
You cannot enforce that the method passed has the right name, but looks even neater IMHO.
You need to understand what generics are.
interface
public interface SomeInterface {
void someStaticMethod();
}
use
class MyClass<T extends SomeInterface>{
T classToRun;
public MyClass(T c) {
super();
this.classToRun = c;
}
public void runClass(){
classToRun.someStaticMethod();
}
}
As 2 of 3 answers were not to the point, I decided to publish fixed versions of both answers as far as they can be fixed.
The f1sh version from the above should like follows:
public class ClassToRunOthers {
Class classToRun;
public ClassToRunOthers(Class c) {
this.classToRun = c;
}
public void runClass() throws Exception {
Optional<Method> method = Arrays.stream(classToRun.getDeclaredMethods()).filter(m -> m.getName().equals("someStaticMethod")).findFirst();
if(!method.isPresent()) {
throw new RuntimeException();
}
method.get().invoke(null);
}
public static void main(String[] args) throws Exception {
ClassToRunOthers mc = new ClassToRunOthers(SomeClass.class);
mc.runClass();
}
}
class SomeClass {
static void someStaticMethod() {
System.out.println("test");
}
}
The zwei solution above can not be fixed without reflection, as generics is not to the point. Evan if you try to parametrize not with SomeInerface (because SomeClass does not extend a common SomeInterface), but with Object, it is still won't solve the problem:
public class MyClass<T extends Object> {
T classToRun;
public MyClass(T c) {
super();
this.classToRun = c;
}
public void runClass() {
// classToRun.someStaticMethod(); // Cannot resolve method 'someStaticMethod' in 'T'
}
public static void main(String[] args) {
MyClass mc = new MyClass(SomeClass.class);
}
}
class SomeClass {
static void someStaticMethod() {
System.out.println("test");
}
}
This can be fixed like the above, via reflection.
I believe, it can be done with annotations in some elegant way, and may be someone will share us with such a solution or I will do it by myself as time permits.
By now for myself, a solution with saving class name in the String in constructor next day after the question been asked did the trick.
You will have to use reflection if you want to execute a method when you only have the Class instance.
In the code below, runClass finds the method of the class using it's name as a String, then executes it. This code assumes that the method is static, also ignoring any Exception handling.
The following code prints "test":
class MyClass {
Class classToRun;
public MyClass(Class c) {
this.classToRun = c;
}
public void runClass() throws Exception {
Optional<Method> method = Arrays.stream(classToRun.getDeclaredMethods()).filter(m -> m.getName().equals("someStaticMethod")).findFirst();
if(!method.isPresent()) {
throw new RuntimeException();
}
method.get().invoke(null);
}
}
class Main {
public static void main(String[] args) throws Exception {
MyClass mc = new MyClass(Main.class);
mc.runClass();
}
static void someStaticMethod() {
System.out.println("test");
}
}
In java, I'd like to do something like this
public class Tata{
public static void f(){
//something
}
public static void g(){
//something
}
}
public class Titi{
public static void f(){
//something
}
public static void g(){
//something
}
}
public class Toto{
private Class c = Tata.class; //or Titi.class
public static void main(String[] args) {
c.f();
c.g();
}
}
To be precise, I'd like to be able to freely switch between classes Tata and Titi, to use their respective methods f or g.
This doesn't work as intended, as I get the cannot resolve method 'f()' error. Simply replacing c.f(); and c.g(); with Tata.f(); and Tata.g(); works fine, but defeats the purpose of using a parameter. How to solve this?
Will turn the comment into answer after all.. The correct (Java) way to deal with what you want is the use of interface. So in your demo code the implementation would be the following:
public interface TheFGFunctions {
void f();
void g();
}
public class Tata implements TheFGFunctions {
#Override
public void f() {
//something
}
#Override
public void g() {
//something
}
}
public class Titi implements TheFGFunctions {
#Override
public void f() {
//something
}
#Override
public void g() {
//something
}
}
public class Toto {
private TheFGFunctions c;
public Toto(TheFGFunctions c) {
this.c = c;
}
public void notStaticFunction() {
c.f();
c.g();
}
}
This way is totally typesafe with zero exceptions to deal with!
You cannot access a static method polymorphically. The Java language doesn't support it.
The reason your current approach fails is that c is an instance of the class Class, and the class Class doesn't define methods f() or g().
(The methods that it does define are listed in the javadoc for Class. Note that Class is final so you can't create a custom subclass with extra methods.)
The simple alternative is to use reflection; e.g.
Class c =
Method f = c.getMethod("f");
f.invoke(null); // because it is static
But note:
This is not statically type-safe. The compiler cannot tell when you make the mistake of trying to use a static f() on a class that doesn't have such a method.
There are a few exceptions that you need to deal with; e.g. missing methods, incorrect signatures, methods that are not static, methods that don't have the correct access.
Other answers have proposed creating an interface and wrapper classes to make certain static methods dispatchable. It will work and it will be compile-time type-safe (!) but there is a lot of boiler plate code to write.
#Michael Michailidis commented:
Thus interfaces!
Yea ... kind of. You can only dispatch polymorphically on instance methods declared on an interface. That implies that you must have an instance of Tata or Titi, and call the methods on it. My reading of the Question is that the author wants to avoid that.
(IMO, the avoidance is the real problem. You are better of not trying to avoid instance methods.)
FWIW, you can declare static methods in an interface (since Java 8), but they would behave the same as if you declared them in a class. You wouldn't be able to dispatch ...
You could use reflections:
private Class c = Tata.class;
public Toto() throws Exception {
c.getMethod("f").invoke(null);
c.getMethod("g").invoke(null);
}
Here my Tata class
public class Tata {
public static void f() {
System.out.println("ffff");
}
public static void g() {
System.out.println("gggg");
}
}
Output on new Toto() call:
ffff
gggg
Update (call with parameters):
public Toto() throws Exception {
c.getMethod("f", String.class).invoke(null, "paramValue1");
c.getMethod("g", String.class).invoke(null, "paramValue2");
}
public class Tata {
public static void f(String param1) {
System.out.println("ffff " + param1);
}
public static void g(String param2) {
System.out.println("gggg " + param2);
}
}
Output:
ffff paramValue1
gggg paramValue2
Write a wrapper interface
interface CWrapper {
void f();
void g();
}
and wrapper class factory method for each Class containing the methods
class CWrappers {
CWrapper forTiti(Class<Titi> titiClass) {
return new CWrapper() {
void f() { Titi.f(); }
void g() { Titi.g(); }
}
}
// another factory method for Tata
}
Then you can use that:
public class Toto {
private CWrapper c = CWrappers.forTata(Tata.class); //or forTiti(Titi.class)
public static void main(String[] args) {
c.f();
c.g();
}
}
Since Java 7, we can catch multiple exceptions in the same catch clause like the following.
try {
...
} catch( IOException | SQLException ex ) {
...
}
Similarly, Is there any way to implement like the following without using Inheritance?
public void passMultipleTypes(Type1 | Type2 obj) {
...
}
The obj object can either be Type1 or Type2. I do not want to use inheritance here as these classes are generated and I cannot change them. So I cannot define them as
public class Test1 extends CommonSuperClass {
...
}
Type1 and Type2 have similar attributes. So I was thinking of working with obj like the following.
public void passMultipleTypes(Type1 | Type2 obj) {
System.out.println(obj.getCode());
System.out.println(obj.getValue());
}
Since classes are generated as part of some code gen plugin.
You can use composition along with inheritance to solve this issue.
Write wrapper class for Type1 and Type2 extending to common interface.
This will provide code reusability as well as act as a layer between apllicaton code and 3rd party API.
public class Testing {
public static void main(String[] args) {
Processor processor = new Processor();
processor.passMultipleTypes(new Type1Wraper());
processor.passMultipleTypes(new Type2Wrapper());
}
}
interface BasicType {
void operationOne();
void operationTwo();
}
class Type1 {
}
class Type2 {
}
class Type1Wraper implements BasicType {
private Type1 type;
#Override
public void operationOne() {
// type 1 method
}
#Override
public void operationTwo() {
// type 1 method
}
}
class Type2Wrapper implements BasicType {
private Type2 type;
#Override
public void operationOne() {
// type 2 method
}
#Override
public void operationTwo() {
// type 2 method
}
}
class Processor {
public void passMultipleTypes(BasicType object) {
object.operationOne();
object.operationTwo();
}
Since you don't want to use inheritance, you could use method overloading.
public void passMultipleTypes(Type1 obj) {
...
}
public void passMultipleTypes(Type2 obj) {
...
}
If you pass an argument of Type1, the first method would be called. If the argument is of Type2, the second would be called.
If you cannot change classes Type1 and Type2 then just use overloading of method:
public void passMultipleTypes(Type1 obj) {
System.out.println(obj.getCode());
System.out.println(obj.getValue());
}
public void passMultipleTypes(Type2 obj) {
System.out.println(obj.getCode());
System.out.println(obj.getValue());
}
"But code duplicates...." yes, that is right. There will be some duplicates of code. But because you cannot change original code then you cannot solve it in nice way. Just move duplication to another place.
You can define a cutom type like Either class in Scala:
class Or<L,R>
{
private final Optional<L> left;
private final Optional<R> right;
...
}
So you can use this class like this:
public void passMultipleTypes(Or<Type1, Type2> obj) {
if(obj.isLeft()) {
} else {
}
}
I am trying to provide a callback to a class function written in Java by means of an anonymous abstract class instance, but from a groovy class. The code below illustrate my issue.
//Java Code
abstract class CallBackWrapper
{
int someAttr, someOtherAttr;
public abstract void execute();
public int getAttr()
{
return someAttr;
}
}
class Delegator
{
public void callExecute(CallBackWrapper w)
{
w.execute();
}
}
//Groovy Code
class GroovyClass
{
private void foo()
{
//Doesn't work
Delegator d = new Delegator();
d.callExecute(new CallBackWrapper() {
public void execute() {
System.out.println("Hello World");
}
});
//Also doesn't work
Delegator d = new Delegator();
d.callExecute([execute:{println "HELLO from Groovy"}] as CallBackWrapper)
}
}
The closest I got to getting it to work is by changing CallBackWrapper to an interface AND declaring it inside the Groovy class. However, I need an abstract class. My question is, how can I implement this callback behavior from "Groovy Land" so that the Java class understands? Currently I get Groovy runtime errors that are not very helpful in explaining the true nature of the issue.
You haven't specified your error, but I tried your code here and got the following error:
$ javac *.java && groovy GroovyClass.groovy && rm *.class
Caught: java.lang.IllegalAccessError: class GroovyClass$1 cannot access its superclass CallBackWrapper
java.lang.IllegalAccessError: class GroovyClass$1 cannot access its superclass CallBackWrapper
It happened due to Groovy's generated inner class being unable to access CallBackWrapper. I added the public modifier and it worked fine:
// Delegator.java
class Delegator {
public void callExecute(CallBackWrapper w) {
w.execute();
}
}
// CallBackWrapper.java
public abstract class CallBackWrapper {
int someAttr, someOtherAttr;
public abstract void execute();
public int getAttr()
{
return someAttr;
}
}
// GroovyClass.groovy
class GroovyClass
{
private void foo() {
def d = new Delegator()
d.callExecute { println "Hello from groovy" }
}
static main(args) {
new GroovyClass().foo()
}
}
Out of curiosity, I added Delegator::me() to Java code, invoked it from Groovy and it worked:
class Delegator {
public void callExecute(CallBackWrapper w) {
w.execute();
}
void me() {
new CallBackWrapper() {
public void execute() {
System.out.println("Echo");
}
}.execute();
}
}
Seems to me like a bug similar to this one. You could fill a jira.
I have a number of classes that define a method, and I want to execute some code (say, some "prologue" and "epilogue") around that method:
public interface Thing {
public void stuff();
public void callStuff();
}
public abstract class Something implements Thing {
public abstract void stuff();
public void callStuff() {
... // common prologue
//try {
stuff();
//} finally {
... // common epilogue
//}
}
}
public class A extends Something {
public void stuff() { ... }
}
public class B extends Something {
public void stuff() { ... }
}
public class Wrapper extends Thing {
private Thing t;
Wrapper(Thing thing) { t = thing; }
public void stuff() { t.stuff(); }
public void callStuff() { t.callStuff(); }
}
// Use:
Something s = ...;
s.callStuff();
You see that the idea is that subclasses will redefine stuff() while the clients will invoke callStuff(). Nevertheless, in some rare cases one has to call stuff(), see Wrapper above.
Something like that we see in the Thread class (since JDK 1.0), child classes redefine run() but the clients invoke start().
How do I prevent clients from calling stuff() directly?
EDIT
protected does not work here because the "clients" really are children of Something coded by another team. #Deprecated would work, but stuff() is not really deprecated, and everyone knows what "deprecated" is, so I cannot redefine the meaning of #Deprecated.
Ideally, the compilation should fail unless an explicit directive is given to ignore the problem.