Is there an explicit way to override a Java method in JRuby-subclass?
public class Yours {
public String hi() {
return "Hello original";
}
}
In a Java I'd use #override to make subclassing explicit.
public class Mine extends Yours {
#Override // throws an error if the above is not a superclass method
public String hi() {
return "Hello override!";
}
}
When I override this in Jruby, I'd like something like this:
class JRMine < Yours
java_overrides # I wish this was there, making sure "wiring" is ok
def hi()
"Hello Jruby"
end
end
Now, is there any equivalent technique to achieve safe overriding?
It seems it could avoid some hard-to-track errors in java integration, due to just relying on method naming.
(Actually I find it would be handy in Ruby generally too, to a lesser extent..)
UPDATE: now packed into gem 'overrides' https://github.com/kares/overrides
with a bit of meta-programming this is possible to do with Ruby methods (and works with JRuby since Java inherited methods show up as Ruby ones) ... I've put it up in a gist :
https://gist.github.com/kares/7434811 ... now that someone finds it useful might put it in a gem :)
usage sample (NOTE: you do not need to hook it up for all classes/modules) JRuby style :
Object.extend Override
class JList < java.util.ArrayList
override
def trim_to_size; super; end
def isEmpty; false; end
override :isEmpty
end
Related
The simplest code to demonstrate the issue is this:
Main interface in Kotlin:
interface Base <T : Any> {
fun go(field: T)
}
Abstract class implementing it and the method:
abstract class Impl : Base<Int> {
override fun go(field: Int) {}
}
Java class:
public class JavaImpl extends Impl {
}
It should work, but it doesn't. The error is
Class 'JavaImpl' must either be declared abstract or implement abstract method 'go(T)' in 'Base'
If the JavaImpl class was in Kotlin, it would work. Also if the T was cast to String or Integer or any object, it would work too. But not with Int.
Is there any clever solution apart from using Integer and suppressing hundreds of warnings in Kotlin subclasses?
Update: created the issue.
Looking at the byte code we can see, that the Impl-class basically has produced the following function:
public go(I)V
where the parameter is a primitive integer. Also a synthetic bridge-function (go(Object)) is generated, which however would also be generated on the Java-side for such generic functions.
On the Java side however it doesn't suffice to have something like public void go(int field) in place. Now we need that go(Integer field)-function, which isn't present.
For me that sound's like an interop-problem that should probably be reported and linked back here again. Actually having had some time to investigate, there seem to be some issues already: KT-17159 and KT-30419, but also KT-5128 seem to relate to this problem. The kotlin compiler knows how to deal with this and doesn't need any further information about it in the class-file (i.e. the implementing Kotlin class knows, that it doesn't need to implement something like fun go(field : Int?)). For the Java-side such counterpart does not exist. I wonder whether this could even be fixed nicely with the compiler/byte-code or whether this will remain a specific interop-problem.
Some workarounds to deal with that problem (in case this is deliberate and not a real problem):
Add an additional function as follows to Impl:
fun go(field : Int?) = go(field ?: error("Actually the given field should never be null"))
// or simply:
fun go(field : Int?) = go(field!!)
That way you would not need to implement it. However then you would also expose that nullable function to the Kotlin side, which you probably don't want.
For that specific purpose it may seem more convenient to do it the other way around:
declare the class and the interface in Java and use it on the Kotlin side. That way you could still declare something like
abstract class KotlinClass : JavaInterface<Int> {
override fun go(field : Int) { // an IDE might suggest you to use Int? here...
// ...
}
}
You can use javap to analyze the problem, showing members of compiled interface and classes.
javap Base
public interface Base<T> {
public abstract void go(T);
}
javap Impl
public abstract class Impl implements Base<java.lang.Integer> {
public void go(int);
public void go(java.lang.Object);
public Impl();
}
So, the problem is exactly that pointed out by #Roland: in order to satisfay the contract requested by the Base interface, the Java compiler needs a public void go(java.lang.Integer) method but the method generated by Kotlin compiler has int as parameter.
If you implement the interface in Java, with something like
class JI implements Base<Integer> {
#Override
public void go(#NotNull Integer field) {
}
}
you can analyze its compiled version with javap obtaining
javap JI
class JI implements Base<java.lang.Integer> {
org.amicofragile.learning.kt.JI();
public void go(java.lang.Integer);
public void go(java.lang.Object);
}
So, if you plan to use Kotlin class Impl as superclass of Java classes, the solution is simply to use <Integer>, not <Int>, as type parameter: Int is a Kotlin class, translated to int by the compiler; Integer is the Java class you usually use in Java code.
Changing your example to
abstract class Impl : Base<Integer> {
override fun go(field: Integer) {}
}
public class JavaImpl extends Impl {
}
the JavaImpl Java class compiles without errors.
I'm having some troubles overriding a java method from a jruby class. Since JRuby exposes java methods with both camel and snake case syntaxes, i've tried both approaches to override the same method, but i'm having strange results:
JAVA
package tabaqui;
class MyJavaClass {
public void myMethod() {
System.out.println("Java method");
}
public void invokeMyMethod() {
myMethod();
}
}
RUBY
class MyRubyClass1 < Java::tabaqui.MyJavaClass
def my_method
puts "Ruby method from MyRubyClass1\n";
end
end
class MyRubyClass2 < Java::tabaqui.MyJavaClass
def myMethod
puts "Ruby method from MyRubyClass2\n";
end
end
a = MyRubyClass1.new
a.my_method #output: "Ruby method from MyRubyClass1"
a.invoke_my_method #output: "Java method"
b = MyRubyClass2.new
b.my_method #output: "Java method"
b.invoke_my_method #output: "Ruby method from MyRubyClass2"
The only solution i've found to obtain the expected result (ruby methods invoked in every case) is giving the overridden method an alias after defining it in ruby:
alias_method :myMethod, :my_method
Am i doing something wrong?
while confusing at first sight, this is "expected" once you understand alias ...
MyJavaClass#myMethod will have a my_method alias setup by the JRuby runtime.
in MyRubyClass1 you redefined my_method (alias) thus seeing the expected output.
however you did not override myMethod -> the convention does not work backwards.
while in MyRubyClass2 you redefined myMethod so it ends up doing virtual Java dispatch from invokeMyMethod(), es expected.
while this might seem confusing its how it is, the Java alias conventions are really there for "bare" consumers. while if you're extending a Java class you should stick to proper Java names. there's room for improvement here to re-define Java aliases once a proxy class is generated, although it might be a breaking change.
I use ASM to update the class stack map, but when asm getMergedType, the following exception occurs:
java.lang.RuntimeException:
java.io.IOException: Resource not found for IntefaceImplA.
If without asm modify the class method, it does work fine.
I have defined two interfaces A and B: IntefaceImplA and
IntefaceImplB.
My environment source code:
IntefaceA.java
public interface IntefaceA {
void inteface();
}
IntefaceImplA.java
public class IntefaceImplA implements IntefaceA {
#Override
public void inteface() {
}
}
IntefaceImplB.java
public class IntefaceImplB implements IntefaceA {
#Override
public void inteface() {
}
}
Test.java
public class Test {
public IntefaceA getImpl(boolean b) {
IntefaceA a = b ? new IntefaceImplA() : new IntefaceImplB();
return a;
}
}
Main.java
public class Main {
public static void main(String args[]) {
....
if (a instance of Test) {
..
...
}
}
}
After I compiled a runner jar, and delete the IntefaceImplA.class and IntefaceA.class manually from the jar. why i wanna to delete those classes files, since the spring always like to do this stuff.
the runner jar can be run normal without ASM, but use Asm will occur exception. since the asm wanna to getMergedType for IntefaceImplA and IntefaceImplB, but IntefaceImplA was deleted by me.
After investigate the ASM ClassWriter source code i found below code:
protected String getCommonSuperClass(String type1, String type2)
{
ClassLoader classLoader = this.getClass().getClassLoader();
Class c;
Class d;
try {
c = Class.forName(type1.replace('/', '.'), false, classLoader);
d = Class.forName(type2.replace('/', '.'), false, classLoader);
} catch (Exception var7) {
throw new RuntimeException(var7.toString());
}
if(c.isAssignableFrom(d)) {
return type1;
} else if(d.isAssignableFrom(c)) {
return type2;
} else if(!c.isInterface() && !d.isInterface()) {
do {
c = c.getSuperclass();
} while(!c.isAssignableFrom(d));
return c.getName().replace('.', '/');
} else {
return "java/lang/Object";
}
}
Actually, I deleted the related class file, the classloader cannot find the class. but without asm the Program does work normal.
Should I enhance the override to the getCommonSuperClass method, if occur exception then return java/lang/Object for it? that's funny
Generally, overriding getCommonSuperClass to use a different strategy, e.g. without loading the class, is a valid use case. As it’s documentation states:
The default implementation of this method loads the two given classes and uses the java.lang.Class methods to find the common super class. It can be overridden to compute this common super type in other ways, in particular without actually loading any class, or to take into account the class that is currently being generated by this ClassWriter, which can of course not be loaded since it is under construction.
Besides the possibility that either or both arguments are classes you are currently constructing (or changing substantially), it might be the case that the context of the code transforming tool is not the context in which the classes will eventually run, so they don’t have to be accessible via Class.forName in that context. Since Class.forName uses the caller’s context, which is ASM’s ClassWriter, it is even possible that ASM can’t access the class despite it is available in the context of the code using ASM (if different class loaders are involved).
Another valid scenario is to have a more efficient way to resolve the request by using already available meta information without actually loading the class.
But, of course, it is not a valid resolution to just return "java/lang/Object". While this is indeed a common super type of every argument, it isn’t necessarily the right type for the code. To stay with your example,
public IntefaceA getImpl(boolean b) {
IntefaceA a = b ? new IntefaceImplA() : new IntefaceImplB();
return a;
}
the common super type of IntefaceImplA and IntefaceImplB is not only required to verify the validity of assigning either type to it, it is also the result type of the conditional expression, which must be assignable to the return type of the method. If you use java/lang/Object as common super type, a verifier will reject the code as it can’t be assignable to IntefaceA.
The original stackmap, very likely reporting IntefaceA as common super, will be accepted by the verifier as that type is identical to the method’s return type, so it can be considered assignable, even without loading the type. The test, whether either, IntefaceImplA and IntefaceImplB, is assignable to that specified common type, might be postponed to the point where these types are actually loaded and since you said, you deleted IntefaceA, this can never happen.
A method whose declared return type is absent, can’t work at all. The only explanation of your observation that “without asm the program does work normal”, is, that this method was never invoked at all during your test. You most probably created a time bomb in your software by deleting classes in use.
It’s not clear why you did this. Your explanation “since the spring always like to do this stuff” is far away from being comprehensible.
But you can use the overriding approach to get the same behavior as with the unmodified code. It just doesn’t work by return java/lang/Object. You could use
#Override
protected String getCommonSuperClass(String type1, String type2) {
if(type1.matches("IntefaceImpl[AB]") && type2.matches("IntefaceImpl[AB]"))
return "IntefaceA";
return super.getCommonSuperClass(type1, type2);
}
Of course, if you deleted more class files, you have to add more special cases.
An entirely different approach is not to use the COMPUTE_FRAMES option. This option implies that ASM will recompute all stack map frames from scratch, which is great for the lazy programmer, but implies a lot of unnecessary work if you are just doing little code transformations on an existing class and, of course, creates the requirement to have a working getCommonSuperClass method.
Without that option, the ClassWriter will just reproduce the frames the ClassReader reports, so all unchanged methods will also have unchanged stack maps. You will have to care about the methods whose code you change, but for a lot of typical code transformation tasks, you can still keep the original frames. E.g. if you just redirect method calls to signature-compatible targets or inject logging statements which leave the stack in the same state it was before them, you can still keep the original frames, which happens automatically. Note the existence of the ClassWriter(ClassReader,int) constructor, which allows an even more efficient transfer of the methods you don’t change.
Only if you change the branch structure or insert code with branches, you have to care for frames. But even then, it’s often worth learning how to do this, as the automatic calculation is quiet expensive while you usually have the necessary information already when doing a code transformation.
I want to inject some code through annotations in java.
The plan is I have two methods beginAction() and endAction(). I want to annotate a method such that before executing the statements in the method the beginAction() will be put and after finishing executing them the endAction() will be put automatically. Is it possible. If yes please suggest me how to do.
#MyAnnotation
public void myMethod(){
// Statement 1;
// Statement 2;
}
At runtime the beginAction() and endAction() should be injected in the method through the annotation. That is it should become like the following at runtime.
public void myMethod{
beginAction();
// Statement 1;
// Statement 2;
endAction();
}
It looks like you need aspects. AspectJ is the most popular library in this case. You can read more about it here: https://eclipse.org/aspectj/docs.php
And here's the example of such aspect in use:
Class with intercepted method:
public class YourClass {
public void yourMethod() {
// Method's code
}
}
Aspect itself:
#Aspect
public class LoggingAspect {
#Around("execution(* your.package.YourClass.yourMethod(..))")
public void logAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("Do something before YourClass.yourMethod");
joinPoint.proceed(); //continue on the intercepted method
System.out.println("Do something after YourClass.yourMethod");
}
}
You can't do it using just plain Java. However, there is a Java-like language that does allow this. It's called Xtend. It compiles to Java, not bytecode, so it benefits from all the wonderful things your Java compiler does.
It started life as an Eclipse project, but is now also available for IntelliJ.
One of its many features is a thing called "Active Annotations". They do exactly what you're asking for: they allow you to participate in the code generation process, so you can insert your beginAction() and endAction() methods as you want.
See http://www.eclipse.org/xtend/documentation/204_activeannotations.html for more info on Active Annotations.
I would like to write a code internal to my method that print which method/class has invoked it.
(My assumption is that I can't change anything but my method..)
How about other programming languages?
EDIT: Thanks guys, how about JavaScript? python? C++?
This is specific to Java.
You can use Thread.currentThread().getStackTrace(). This will return an array of StackTraceElements.
The 2nd element in the array will be the calling method.
Example:
public void methodThatPrintsCaller() {
StackTraceElement elem = Thread.currentThread.getStackTrace()[2];
System.out.println(elem);
// rest of you code
}
If all you want to do is print out the stack trace and go hunting for the class, use
Thread.dumpStack();
See the API doc.
Justin has the general case down; I wanted to mention two special cases demonstrated by this snippit:
import java.util.Comparator;
public class WhoCalledMe {
public static void main(String[] args) {
((Comparator)(new SomeReifiedGeneric())).compare(null, null);
new WhoCalledMe().new SomeInnerClass().someInnerMethod();
}
public static StackTraceElement getCaller() {
//since it's a library function we use 3 instead of 2 to ignore ourself
return Thread.currentThread().getStackTrace()[3];
}
private void somePrivateMethod() {
System.out.println("somePrivateMethod() called by: " + WhoCalledMe.getCaller());
}
private class SomeInnerClass {
public void someInnerMethod() {
somePrivateMethod();
}
}
}
class SomeReifiedGeneric implements Comparator<SomeReifiedGeneric> {
public int compare(SomeReifiedGeneric o1, SomeReifiedGeneric o2) {
System.out.println("SomeRefiedGeneric.compare() called by: " + WhoCalledMe.getCaller());
return 0;
}
}
This prints:
SomeRefiedGeneric.compare() called by: SomeReifiedGeneric.compare(WhoCalledMe.java:1)
somePrivateMethod() called by: WhoCalledMe.access$0(WhoCalledMe.java:14)
Even though the first is called "directly" from main() and the second from SomeInnerClass.someInnerMethod(). These are two cases where there is a transparent call made in between the two methods.
In the first case, this is because we are calling the bridge method to a generic method, added by the compiler to ensure SomeReifiedGeneric can be used as a raw type.
In the second case, it is because we are calling a private member of WhoCalledMe from an inner class. To accomplish this, the compiler adds a synthetic method as a go-between to override the visibility problems.
the sequence of method calls is located in stack. this is how you get the stack: Get current stack trace in Java then get previous item.
Since you asked about other languages, Tcl gives you a command (info level) that lets you examine the call stack. For example, [info level -1] returns the caller of the current procedure, as well as the arguments used to call the current procedure.
In Python you use the inspect module.
Getting the function's name and file name is easy, as you see in the example below.
Getting the function itself is more work. I think you could use the __import__ function to import the caller's module. However you must somehow convert the filename to a valid module name.
import inspect
def find_caller():
caller_frame = inspect.currentframe().f_back
print "Called by function:", caller_frame.f_code.co_name
print "In file :", caller_frame.f_code.co_filename
#Alternative, probably more portable way
#print inspect.getframeinfo(caller_frame)
def foo():
find_caller()
foo()
Yes, it is possible.
Have a look at Thread.getStackTrace()
In Python, you should use the traceback or inspect modules. These will modules will shield you from the implementation details of the interpreter, which can differ even today (e.g. IronPython, Jython) and may change even more in the future. The way these modules do it under the standard Python interpreter today, however, is with sys._getframe(). In particular, sys._getframe(1).f_code.co_name provides the information you want.