Strange behaviour on method annotations and default access level - java

Here's my problem...
I have an annotation in package pkg3:
package pkg3;
import java.lang.annotation.*;
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface TestAnno {
}
Also I have two classes in package pkg1, one with public access and one with default access
package pkg1;
import pkg3.TestAnno;
class Class1 {
#TestAnno
public void test1() { }
public void test2() { }
}
and
package pkg1;
import pkg3.TestAnno;
public class Class2 extends Class1 {
#TestAnno
public void test3() { }
public void test4() { }
}
Finnally I've got a main class in package pkg2
package pkg2;
import java.lang.reflect.Method;
import pkg1.Class2;
import pkg3.TestAnno;
public class MainClass {
public static void main(String[] args) {
Class2 cls = new Class2();
for(Method m: cls.getClass().getMethods()) {
System.out.println(m);
if (m.getAnnotation(TestAnno.class) != null) {
System.out.println(" > hass anno");
}
}
}
}
Running this example I expect to see the info, that two methods have #TestAnno present - test1 and test3, but I only see one test3, and... what is strange, the methods test1 and test2 are listed as they were be declared in class Class2.
public void pkg1.Class2.test3()
> hass anno
public void pkg1.Class2.test4()
public void pkg1.Class2.test1()
public void pkg1.Class2.test2()
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
... rest methods from java.lang.Object
I know, that getMethods returns only public methods from given glass (and it's all super classes) but... this is strange for me.
I'm using this in order to separate generated classes (which have default access) from implementation classes (which are public and they're extending generated classes).
Have I to use public access in generated classes (I wanted them not to be visible to rest of the world) or is there any way to get annotated public methods from Class1 ?

This answer is just a "one big maybe" made by a man at 3 a.m. so it will require JLS confrontation, better terminology and more informations. I was planning to post it as comment but unfortunately it is too long :/
Lets take a look at this classes
class SomeClass {
#TestAnno
public void test(){}
}
class SomeDefaultClass extends SomeClass {
}
public class SomePublicClass extends SomeClass {
}
now take a look at this code and its result
Method m1 = SomePublicClass.class.getMethod("test");
Method m2 = SomeDefaultClass.class.getMethod("test");
System.out.println(m1 + "\t> " + m1.getAnnotation(TestAnno.class));
System.out.println(m2 + "\t\t> " + m2.getAnnotation(TestAnno.class));
output
public void SomePublicClass.test() > null
public void SomeClass.test() > #TestAnno()
As you see public class that extends class with package modifier doesn't inherit annotations, but class with package modifier does.
Why is that?
Both SomeDefaultClass and SomePublicClass "inherited" test() method but not in the same way.
If you take a look at result of javap SomeDefaultClass.class you will see
class SomeDefaultClass extends SomeClass {
SomeDefaultClass();
}
so it doesn't have test() method in its binaries, so it will use it from SomeClass which have TestAnno annotation.
On the other hand if you take a look at result of javap SomePublicClass you will see
public class SomePublicClass extends SomeClass {
public SomePublicClass();
public void test();
}
which means that code of test() method has been overridden in SomePublicClass so this method has been declared again in SomePublicClass but unfortunately without previous annotations and since overridden method doesn't have annotations you wont see them in your code. (Why annotations are not added when compiler is overriding method? Honestly, I don't know :/)
Why is overriding happening? I suspect that since SomePublicClass is public and test is also public it should be accessible from all packages, but since SomeClass has default/package visibility this method couldn't be accessible via SomeClass from outside of its package.
To prevent moving/copying test method from one class to another you can make both classes public or default/package.

Related

Override Java methods in Python using Pyjnius

I would like to use Pyjnius to create a Python class that extends a Java class and overrides some of its methods.
Specifically, these Java classes:
public class A {
public void test_method() {
System.out.println("In parent test_method!!!");
}
public static void run(A a) {
System.out.println("Running...");
a.test_method();
}
}
and
public class B extends A {
public void test_method() {
System.out.println("test method");
}
public static void main(String[] args) {
A.run(new B());
}
}
When I run that I see:
Running...
test method
How do I re-implement B in Python using Pyjnius?
This is my attempt:
import jnius_config
jnius_config.set_classpath('jars/testClasses.jar')
from jnius import autoclass, PythonJavaClass, JavaClass, MetaJavaClass, java_method
A = autoclass('test.pyjnius.A')
class B(A):
__javaclass__ = 'test/pyjnius/A'
#java_method('()Z')
def test_method(self):
print("test method")
A.run(B())
When I run the Python version I see this:
Running...
In parent test_method!!!
It isn't properly overriding test_method. How do I fix that?
The answer here is that what I am trying to do is not possible. The JVM cannot call the a method implemented in a Python subclass because it doesn't even know it exists.
The workaround is to implement the run method in class B, but make accommodations for the subclass's method. Something like this:
class B(A):
__javaclass__ = 'test/pyjnius/A'
#java_method('()Z')
def test_method(self):
print("test method")
def run(self):
A.runPart1(self)
self.test_method()
A.runPart2(self)
With runPart1 and runPart2 implemented in Java in a modified version of class A.

How to create a template class file in java

I am creating a test automation framework using selenium & TestNG. This Framework will be use by all of the other team member. Want to specify a class template for all the team member so that basic structure of the test class will same for all and reduce the effort for writing the same structure for all test.
Whenever any member create any class in a particular package the class will be created with some predefined code like below
package com.xxx.yyy.testmodule.dummytest;
import org.testng.annotations.Test;
import com.xxx.yyy.lib.zzz.CommonLib;
public class Test3 extends CommonUtilCommonLibities{
#Test(description="", groups= {""})
public void testTest3() {
//Read Test Data Here
//Test Logic
//Test Verification
}
}
Use an abstract class :
package com.xxx.yyy.testmodule.dummytest;
import org.testng.annotations.Test;
import com.xxx.yyy.lib.zzz.CommonLib;
public abstract class Test3 extends CommonUtilCommonLibities {
#Test(description="", groups= {""})
public void testTest3() {
//Read Test Data Here
Data data = readTestData();
//Test Logic
test(data);
//Test Verification
testAssertion(data);
}
abstract Data readTestData();
abstract void test(Data data);
abstract void testAssertion(data);
}
Of course this only works if all your data beans extend some base bean which is Data in my example.
If you use Intellij IDEA, you can define a test class template, including your methods. There's a similar question with the instructions.
You may also want to make use of a Template Method pattern:
public abstract class GenericTest<T> {
#Test
public void doTest() {
T data = loadTestData();
this.runTestLogic(data);
this.runAssertions(data);
// something else...
}
protected abstract T loadTestData();
protected abstract void runTestLogic(T result);
protected abstract void runAssertions(T result);
}
Your concrete test classes will extend this generic class and implement the actual testing and data reading logic:
public class ConcreteTest extends GenericTest<Integer> {
#Override
protected Integer loadTestData() {
return 42;
}
#Override
protected void runTestLogic(Integer result) {
System.out.println(result);
}
#Override
protected void runAssertions(Integer result) {
assertEquals(0, result % 2);
}
}

Access property/constant in extended classes

I'm trying to achieve the following:
I have a parent class, with some logic. In the child class, I "redefine" constants/properties. Is there any way to make the child properties accessible by methods defined in the parent class? Or to be more specific - is there any way to force the "out" method to write extended rather than base in the following example?
public class BaseTest {
public static final String x = "base";
public void out() {
System.out.println(x);
}
}
public class ExtendedTest extends BaseTest{
public static final String x = "extended";
}
public class Main {
public static void main(String[] args) {
BaseTest base = new BaseTest();
ExtendedTest extended = new ExtendedTest();
base.out(); // base (as expected)
extended.out(); // base (extended expected)
System.out.println(extended.x); // extended (as expected)
}
}
I come mainly from the world of PHP, where this approach works just fine. Dunno if I'm missing something or if the very design of Java does not allow this.
Thank you.
Note: This is not important whether the property is static or not. I just wanted to be able to override a property of any kind in a child class (just like I can override a method) which, on basis of the answers I've received so far, doesn't seem to be possible in Java. In PHP it is absolutely possible and that was why I asked the question.
static fields are not subject to inheritance. The x in the body of the out() method refers to BaseTest.x. Since you are not overriding out(), the body of the out() method still prints the value of BaseTest.x.
Static members are resolved at compile-time, and adding an ExtendedTest.x does not affect the also-existing BaseTest.x, which is what the BaseTest#out() method is linked to.
To accomplish what you're wanting, you need an overridden method:
public class BaseTest {
public String x() {
return "base";
}
public final void out() {
System.out.println(x());
}
}
public class ExtendedTest extends BaseTest {
#Override
public String x() {
return "extended";
}
}
This pattern is commonly used with an abstract method in the base class or interface to require the subclass to define an attribute such as a name or a key.

How to check if class has methods added by aspect?

Suppose I have a simple class:
public class TestClass {
/*...*/
}
I created an aspect which injects new method to this class:
public aspect TestAspect {
public void TestClass.aspectMethod() {
/*...*/
}
}
Now, how can I check if TestClass has method added by TestAspect in runtime?
The simplest way would be to simply reflect on the class:
TestClass.class.getDeclaredMethod("aspectMethod")
which will throw NoSuchMethodException if it isn't there. Or if you have the bytes you could use a byte code visitor to check what methods exist in the byte code - but the reflective route would be less messing around.
Andy's answer is the correct one, I just want to answer your follow-up question from the comment:
Duck typing is not a Java feature, but if you use ITD in order to make the class implement an interface and then have an instance of your aspect-extended class you can use instanceof MyInterface in order to determine what you need to know. Other ways (also using reflection) are also available:
Interface with the method you want to add later via ITD:
package de.scrum_master.app;
public interface MyInterface {
void myMethod();
}
Sample driver application:
package de.scrum_master.app;
import java.lang.reflect.Type;
public class Application {
public static void main(String[] args) {
Application application = new Application();
// Use an instance
System.out.println(application instanceof MyInterface);
System.out.println(MyInterface.class.isInstance(application));
// Use the class
for (Type type : Application.class.getGenericInterfaces())
System.out.println(type);
for (Class<?> clazz : Application.class.getInterfaces())
System.out.println(clazz);
}
}
Aspect:
package de.scrum_master.aspect;
import de.scrum_master.app.Application;
import de.scrum_master.app.MyInterface;
public aspect MyAspect {
declare parents : Application implements MyInterface;
public void Application.myMethod() {}
}
Application output:
true
true
interface de.scrum_master.app.MyInterface
interface de.scrum_master.app.MyInterface

Calling a static method of an abstract class in another class

I have a class Employee
import javax.swing.*;
public abstract class Employee {
public static void searchEmp(int id) {
JOptionPane.showMessageDialog(null, "done");
}
}
Now I have another class test:
public class `test` {
public static void main(String args[]) {
searchEmp(2);// here my programme give error
}
}
I want to call the searchEmp() which is part of Employee from a class test but it gives an error. Please suggest any solution without inheritance.
You have to call Employee.searchEmp().
The static method searchEmp() is still a member of the class Employee and you must make a static call via its class.
Also the class Employee must be visible to the class test, otherwise you have to import it. I assume the two classes reside in the same package so this will not be a problem in your case.
Static methods and properties are bound to class. So you need to use ClassName.methodName or ClassName.propertyName.
Employee.searchEmp();
Your Test class doesnt have a static searchEmp(int) method, thus the error:
searchEmp(2);// here my programme give error
should be
Employee.searchEmp(2);
static methods are called using ClassName.staticMethod()

Categories