Why is this Java method available only using reflection? - java

I'm new to reflection, as a matter of fact, I never had to use it until I ran into the following problem -
I tried to use a method called getCompatibilityInfo defined in a class called Resources, but I saw that the only way of doing it is to call it like this:
Resources.class.getMethod("getCompatibilityInfo");
I can get an instance of Resources using a method called getResources(), so why isn't it accessible using getResources().getCompatibilityInfo()?
The class source code is here
Thanks!

Resources has not an empty public constructor. So new Resources() will give you a compile time error, also getCompatibilityInfo() is not part of the public API

That's something that only happens in Android, because android.jar has all the methods marked with #hide removed. This only matters while compiling, because android.jar is only used for development.
Long explanation on this answer.

Related

How to get the JavaCompiler to use a provided classLoader to find a class?

I am using this code from an old IBM blog post about how to compile and use Java classes at runtime. The code mostly works great (and is quite well written, by the way), but unfortunately for me, it won't work in one of my use cases where the class being compiled refers to another class that can only be provided by the classLoader provided to the CharSequenceCompiler (from the blog post), not by the application classLoader.
To be more specific, The ClassLoader I pass into CharSequenceCompiler is a OSGi classLoader.
The bundle that owns this classLoader can find and return a class, say Foo.
class Foo { public static String FOO = "F"; }
I know this works if you do classLoader.findClass("Foo"); because when I call this from the debugger it works.
Now, from the class I compile at runtime, say Dynamic, I need to use Foo... so I pass the Foo bundle's ClassLoader to CharSequenceCompiler, then ask it to compile Dynamic:
class Dynamic { public static String D = Foo.FOO; }
This causes the following error:
error: cannot find symbol
Foo.FOO;
^
symbol: variable Foo
If Foo is in the same project as CharSequenceCompiler, then it works... so it's clearly a problem loading the class from the right class loader.
I have debugged this code for days (or evenings, tbh) and can't find out why the classLoader I provide to the compiler never even gets asked about this class...
The FileManager is asked to list() the resources in each package, but even when I use the debugger to manually add the FileObject to the returned list, it still won't work.
As the debugger cannot penetrate the native classes used by javac internally, I cannot progress anymore on this... does anyone have inside knowledge of the compiler that could explain what's going on?
I have figured this out after a long battle.
The problem with pretty much all implementations I found of in-memory java compilers based on the java.tools API is that, even though they let you pass in a ClassLoader to load the classes you compile, the classLoader is used only to load new classes, but not to obtain classes that can be used in the Java code being compiled.
For this reason, my use case (as explained in the question) would not work with the code shown in the IBM blog post (or with other projects like OpenHFT Java-Runtime-Compiler).
If you want the classes loaded by the ClassLoader you give to the compiler (which are not visible in the application ClassLoader) to be usable by the class being compiled, you need two things.
First, the ClassLoader classes must be enumerable. This can then be used by the JavaFileManager to implement the list() method properly. For each package, this method must return which classes the ClassLoader could load if required.
Secondly, you need to be able to build JavaFileObjects from the ClassLoader resources, because this is the type of the objects you must return. To do this, you need to ask the ClassLoader for the class's bytecode stream (use getResourceAsStream("Class.class")) and then just create a JavaFileObjectImpl. Basically, this in pseudo-code:
fileObject = new JavaFileObjectImpl( pathMinusDotClass, JavaFileObject.Kind.CLASS );
fileObject.openOutputStream()
.write( classLoader.getInputStream( path ) );
Now, the compiler will know which classes it can load from the provided classLoader and everything works.
I implemented this in a real compiler on my OSGiaaS project, which is not released yet but I plan to do it soon (writing in July 2016)... it includes a Java command in its shell which can run arbitrary Java code, and that's why I needed to get this working.
What is the benefits of using real java compiler. Isn't byte code generation option for you ?
In example: Byte Buddy or cglib

Different behaviour of Class literal and Class.forName for package local classes

Only for example lets consider the class ClassFileAssembler from the sun.reflect package.
This class is a package local class:
class ClassFileAssembler implements sun.reflect.ClassFileConstants {...
So we can not use even its name ClassFileAssembler, we can not import it directly - it will lead to a compiler error.
However we can create a package named sun.reflect in our project and use the ClassFileAssembler name internally in this package - Java compiler will think that we are inside the ClassFileAssembler's package.
If so, why not to try to get a reference to a class object, i.e. ClassFileAssembler.class?
Class<ClassFileAssembler> classFileAssemblerClass = ClassFileAssembler.class;
Unexpectedly this code leads to a run-time error: java.lang.IllegalAccessError: tried to access class sun.reflect.ClassFileAssembler from class sun.reflect.Test.
However we still able to get the ClassFileAssembler class object:
Class<ClassFileAssembler> aClass = (Class<ClassFileAssembler>)Class.forName("sun.reflect.ClassFileAssembler");
It works fine and gives us a full class description.
So, the questions are:
1) What is the difference between techniques, how Class.forName0 retrieves reference to class object, and how .class does it?
2) Why do they have such different security checks?
3) What's the reason to protect .class reference in such way?
4) Do these techniques use different class loaders?
Class.forName don't care about whether a class is package local or not. It is when you attempt to use that class that access is checked. BTW if you do setAccessible(true) you can by pass these access restrictions.
The Reflection library allows you to do many things you cannot do in Java code. The Java has rules as to what you can and cannot do. e.g. you cannot set a final field outside a constructor or more than once. Note: the JVM doesn't have this restriction and at runtime you can use reflections to change it.
The reason this class is package local is to restrict access of the class to code outside this package. This doesn't mean you cannot access it if you really try, but it is less likely you will access it without serious thought being put into it. e.g. when I import classes in my IDE it often suggests classes from com.sun.* which are unlikely to be the right choice. (MY IDE can be set up to ignore these, but I often seem for find some new package I don't want)
The reason Reflections can do this is to support functionality such a Serialization. With Serialization you need to be able to serialize class outside the package of the Serialization library and obtain fields and reset them when deserializing. Reflections is also used by many Inversion of Control libraries though I suspect this is not what they had in mind when they design it.
If you check the javadoc of Class#forName, you will see that:
Note that this method does not check whether the requested class is accessible to its caller.
there is no difference. but you cannot access the static field .class of the package private (no modifier) class ClassFileAssembler.
everyone could access the Class instances, but the fields are protected.
in fact no one designed to protect .class reference this way, it's side effect of protecting other fields.
i dont think so.

coldfusion 9 working with java objects

I'm currently working with the jodatime Java library and running into issues when trying to use it within coldfusion.
I've downloaded the latest jodatime 2.1 release, put the jar file into a folder on my local drive and pointed my coldfusion administrator to look at that folder in the ColdFusion Class Path under the Java and JVM settings page.
For the most part it works. but there are times when i get things like this:
local.oTestZone = createObject('java','org.joda.time.DateTimeZone').init('Europe/London');
Which should match with this: Constructor however I get an error in coldfusion saying:
Unable to find a constructor for class org.joda.time.DateTimeZone that accepts parameters of type ( java.lang.String ).
It works perfectly fine when I do something like this though:
local.oToZone = createObject('java','org.joda.time.DateTimeZone').forID('Europe/London');
Which matches on: forID
Am I missing something with my java implementation?
The DateTimeZone(String id) constructor is marked protected (it took me 3 reads of the JavaDoc to spot that), so CF won't be able to invoke it.
It looks to me like JodaTime expects you to use one of the static methods to construct your instances, so your second example is probably the right way of doing it.
You are dealing with an Abstract Class and a Protected Constructor.
A Protected Constructor means that only a subclass or a class in the same Package can call that constructor. So even though you are supplying the correct parameter, the constructor isn't available to your code.
The ColdFusion documentation has these tidbits:
"Although the cfobject tag loads the class, it does not create an instance object. Only static methods and fields are accessible immediately after the call to cfobject."
This is why forID works; it's a static method.
"To have persistent access to an object, you must use the init function, because it returns a reference to an instance of the object, and cfobject does not."
This and the previous statement are why methods like getOffset wont work in this situation.
I'm not familiar enough with this to know if there's a class that you can instantiate that will give you access to the constructor, but hopefully someone else can chime in.

Making Java Class non-final via Reflection API

I have a Java class similar to the following one:
public final class Node {
public Node() {}
}
I have learned already how to change change the accessibility of 'final' fields via the reflection API, but is this also possible for classes?
Can I turn a final class into a non-final class at runtime?
You can re-write a class file using a library like ASM.
There may be no point changing the final status of a class at runtime as it needs to be non-final at compile time to compile a sub-class.
I don't see how this can work, because the compiler will check to see if the class you're trying to make non-final at compile time. You'll get an error if you try to inherit from it.
I think it's fine to ask the question if you're curious, but the larger question to ask yourself is why do you want to do this? Reflection allows you to do a lot of things to get around final, private, etc., but that doesn't mean it's a good idea. If the designer of a 3rd party library thought that final was a good idea, you might be well advised to honor that.
Edit: Thanks to the comment of #kriegaex. 'accessFlags' field only exists in Class class implementation in Android SDK. Therefore, unless you are developing for Android, this solution will not work for you since such a field does not exist in the first place.
Here is how you can make the class extendable by removing the 'final' modifier:
Class classClass = Class.class;
Field accessFlagsField = classClass.getDeclaredField("accessFlags");
accessFlagsField.setAccessible(true);
Class nodeClass = Node.class;
accessFlagsField.setInt(nodeClass, nodeClass.getModifiers() & ~Modifier.FINAL);
I do not agree with the answers above. One might want to remove the 'final' modifier to extend the class during runtime by using 'ASM' or libraries like 'byte-buddy'. I agree that if it is a final class, it is probably for a good reason but custom business logic may require to do so.

I am not getting code assist for a particular type of object in Eclipse

I have class in one package. and I am creating an instance of this class in another class which is in different package. When i want to use any methods on this object, i can use ctrl+space for code assist which shows all reachable methods which i can use. But in this case it is not showing any, even public setters and getters. So wanted to know am I missing something.
Thanks
You may need to add the package to your build path. Look here: http://www.informit.com/articles/article.aspx?p=367962

Categories