I am attempting to make a custom implementation of Android's StackView by extending AdapterViewAnimator myself. There are several methods contained in AdapterViewAnimator which would prove useful to my subclass, and so I put my subclass in the same package android.widget hoping to gain access to them since they are package-level methods:
void configureViewAnimator(int numVisibleViews, int activeOffset) {
if (activeOffset > numVisibleViews - 1) {
// Throw an exception here.
}
mMaxNumActiveViews = numVisibleViews;
mActiveOffset = activeOffset;
mPreviousViews.clear();
mViewsMap.clear();
removeAllViewsInLayout();
mCurrentWindowStart = 0;
mCurrentWindowEnd = -1;
}
Note that this method is a package level method, which is why my subclass needs to be in android.widget as well. Even so, the compiler (Java 7) tells me that the method does not exist, and so I cannot call the method on my superclass in my class:
package android.widget;
public class Foo extends AdapterViewAnimator {
public void init(){
super.configureViewAnimator(3,1); // Method does not exist.
}
}
Am I missing something here? Why can't my subclass call the superclass package-level method?
You can refer to https://groups.google.com/forum/#!msg/android-developers/poC2Xyh-G4w/zKLBPNTryYMJ
"Android.jar now contains only the public APIs. If you compile against this jar, you are guaranteed your app will run against future versions of Android. As part of the process that removes private APIs from android.jar, the code is stubbed out, because it's never executed so there's no reason to make the SDK much bigger because of it."
This explain why the method configureViewAnimator is not found as you are compiling against the android.jar, which include only public API(configureViewAnimator is a package private method)
Related
I am new to Kotlin and trying out to write some project using the language.
I am using Java library and extending a class from the library in my project and I am seeing this error message.
'public' function exposes its 'public/*package*/' return type argument FooSettings
I understand the problem is but I am not sure how to fix it in Kotlin since I am still trying get familiar with Kotlin.
I can see that Kotlin is being smart and only trying to return of type that extends FooSettings. However the problem is FooSettings is package public only which means that I cannot access if in my Kotlin project.
I did some research about Kotlin generics and use of in or out but I wasn't able to fix the problem.
Is there any work around that I can do in my Kotlin project to fix the error I am seeing?
Code snippet
This is sample of Java library class:
Note, I have no way to changing the implementation of the library. I must use this Library and extend it in Kotlin.
It seems odd to me that the java library is written such a way and expect it to be overridden but that is question for another day.
import java.util.Collections;
import java.util.List;
public abstract class ClassA {
public List<FooBuilder<?>> getBuilder(Foo foo) {
return Collections.emptyList();
}
}
public class Foo {
}
public abstract class FooBuilder<U extends FooBuilder.FooSettings> {
// implementation of Class
abstract static class FooSettings {
// implementation of Class
}
}
Normally Java classes would override the method like such:
import java.util.List;
public class MyJavaClassA extends ClassA {
#Override public List<FooBuilder<?>> getBuilder(final Foo foo) {
// implementation
}
}
But I am trying to write in Kotlin such that it looks like: Reminder that this Kotlin is depending on the Java library and does not have access to package public classes.
class MyKotlinClassA : ClassA() {
override fun getBuilder(foo: Foo): MutableList<FooBuilder<*>> {
// implementation
}
}
This causes error
'public' function exposes its 'public/*package*/' return type argument FooSettings
I presume that by "package public" you meant "package private"? In your example, FooBuilder.FooSettings has no visibility modifier so uses the Java default of package private. Assuming that's what you meant...
You will be able to access the package private class, FooSettings, in your Kotlin code, but only if you put that Kotlin code in a package matching the one where FooSettings is declared.
You'll still get the same compilation error, but that's not because you can't access the type: it's because you're trying to use it in a context which is more visible than the type's declaration. i.e. you're trying to take a package private type and use it as part of a public method's signature, which isn't allowed. To get round that problem you need to mark your Kotlin class as internal.
It's might also be worth mentioning that internal for Kotlin means it's visible in that module, not in that package. This is all explained in more detail here.
In my case, I was getting this error because I was importing a kotlin class variable from another java file which raised because of the auto conversion from java to kotlin by Android Studio.
I was able to fix it by changing all the references of the variable in the java file to its setters and getters.
eg:
// kotlin file
internal open class BubbleBaseLayout : FrameLayout {
var windowManager: WindowManager? = null
lateinit var viewParams: WindowManager.LayoutParams
// defined here
var layoutCoordinator: BubblesLayoutCoordinator? = null
// ...
}
// Java file
// This variable
if (layoutCoordinator != null) { ... }
Needs to be changed to
// layoutCoordinator to getlayoutCoordinator everywhere
if(getlayoutCoordinator() != null){ ... }
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.
For some special use-case I have a small utility to load Java classes from jars using a dynamic class loader DynamicClassLoader. This works fine for Java classes contained in jars. Loading Scala classes from a jar also works without problems. However, instantiating the loaded Scala class leads to the following exception. It looks like the Scala class has private default constructor? Note the compiled Scala class name ending with $
java.lang.IllegalAccessException: Class XXX can not access a member of class ScalaClassYYY$ with modifiers "private"
The snippet below illustrates the idea of what I'm trying to achieve and gives a bit more context. The exception happens at the annotated line:
// deploy and register the new code
byte[] jarBytes = (byte[]) ((Object) message.getAttachment("jar"));
String registerClassName = message.getAttachment("register");
logger.debug("the register is '" + registerClassName + "'");
DynamicClassLoader loader = new DynamicClassLoader(jarBytes);
Class<?> registerClass = loader.lookUp(registerClassName);
// ===> this is where the java.lang.IllegalAccessException happens
IRegisterExecutor registerExecutor = (IRegisterExecutor) registerClass.newInstance();
registerExecutor.register();
Any ideas how to fix?
Obviously, you need to make the default constructor public (it won't work for Java classes without a public default constructor either). E.g.
class ScalaClassYYY() {
...
}
or if you want primary constructor to take some arguments,
class ScalaClassYYY(arg1: Int) {
def this() = this(0)
}
But from
Note the compiled Scala class name ending with $
it seems like you are actually trying to instantiate a Scala object:
object ScalaClassYYY { ... }
In this case, you shouldn't create a new instance and instead use the existing one:
(IRegisterExecutor) registerClass.getField("MODULE$").get(null);
EDIT:
I don't see in your answer how you add a default public constructor to a Scala class that does NOT require any parameters.
A class (not an object) that doesn't require any parameters has a default public constructor already (my first example).
Actually in Java all classes by default offer a public default constructor
No. Only those classes which have no constructors which take arguments.
remove the "(it won't work for Java classes without a public default constructor either)" because it is wrong
The documentation for Class.newInstance() says
IllegalAccessException - if the class or its nullary constructor is not accessible.
So I am pretty sure it's right. If it does work for Java classes without a public default constructor, this seems to be a major bug in the class loader you use. You can test it with a Java class which looks like this:
public class TestClass implements IRegisterExecutor {
public TestClass(int dummy) {}
// some implementation for IRegisterExecutor methods to get it to compile
}
I'm digging through a web application in an effort to fix some problems. The application uses Tomcat, Jersey and Guice. One of the issues is occurring in a MethodInterceptor used for authorization purposes. Here's the method, trimmed to the relevant part:
public Object invoke(MethodInvocation invoc) throws Throwable {
// ...
//Check that the annotation actually exists
if(! invoc.getMethod().getDeclaringClass().isAnnotationPresent(Tool.class))
{
throw new BaseException("...");
}
// ...
}
Now the problem is that some of the "web-facing" methods are inherited from a parent class without being overridden in the child. If I understand getDeclaringClass() correctly, it will return the parent class in this case, but what we really want here is the child class. Some testing seems to confirm this--if I override the method in the child class everything is fine, but if I don't put in the override the exception is thrown.
So, given a MethodInvocation object, is there a way to trace it back to the "actual" class instantiated, rather than the class where the method was declared? Or is some other approach necessary? Worst-case, I could just annotate each method as necessary rather than annotating the class.
Sorry if this is a long-winded question for an easy answer - my Java is pretty rusty.
Simple enough, needed to use getThis().getClass() on the MethodInvocation instead of getMethod().getDeclaringClass():
if(! invoc.getThis().getClass().isAnnotationPresent(Tool.class))
{
throw new BaseException("...");
}
Although in my case, Guice complicated things a bit by putting in an auto-generated child class (e.g., a class name ending in "$$EnhancerByGuice..." That was fixed by moving one up the tree with getSuperclass():
if(! invoc.getThis().getClass().getSuperclass().isAnnotationPresent(Tool.class))
{
throw new BaseException("...");
}
It looks like that the answer is No. I created simple test to check it:
class Run implements Runnable {
#Override
public void run() {
}
}
class Run2 extends Run{}
Method method = Run2.class.getMethods()[0];
System.out.println(method);
As we can see in debug window method doesn't have any information of class Run2:
I guess it would be better to stick on actual methods with its annotations rather then on actual class instances where these methods get invoked.
When decompiling a specific jar using java decompiler (http://java.decompiler.free.fr/) I got some strange code I cannot identify what is. can someone help me? the code is something like:
Foo.access$004(Foo.this);
or this
Bar.access$006(Bar.this);
or else
Baz.access$102(Baz.this, true)
What are these methods access$004, access$006 and access$102?
Synthetic methods like this get created to support acessing private methods of inner classes. Since inner classes were not part of the initial jvm version, the access modifiers could not really handle this case. The solution was to create additional package-visible methods that delegate to the private implementation.
public class Example {
private static class Inner {
private void innerMethod() { ... }
}
public void test() {
Inner inner = ...
inner.innerMethod():
}
}
The compile would create a new method of the Inner class like this:
static void access$000(Inner inner) {
inner.innerMethod();
}
And replace the call in the test method like this:
Inner.access$000(inner);
The static access$000 is package visible and so accessible from the outer class, and being inside the same Inner class it can delegate to the private innerMethod.
These are auto-generated methods which are created by the compiler in some cases (for example when accessing private fields of another class directly, e.g., in case of nested classes).
See also What is the meaning of "static synthetic"? and Synthetic Class in Java.
If you get the relevant .class file (run jar through unzip), and run the .class file through JAD
JAD MyClass.class
then you may find that the output JAD file has decompiled that particular line in a more meaningful way, e.g.
Baz.access$102(Baz.this, true)
shows up in the JAD output as simply
myMemberVaiable = true
where myMemberVaiable is a member of class Baz that you will recognise.