I want to explicitly initialize some classes during the initialization of my application using Class.forName, but in order make that code survive refactorings, I want to use this:
Class.forName(MyClass.class.getName());
I wonder: Wouldn't the class be loaded as soon as the getName method is executed thus making Class.forName unnecessary?
Actually, even the getName() call is unnecessary, since in order for the MyClass.class object to exist, the class has to be loaded and initialized.
Of course, this method means that you have a compile-time dependency on MyClass, which you do not have when using Class.forName() with a String literal.
You can easily check this out. Just add something like this:
static { System.out.println("Class loaded"); }
in the class and try it. Static blocks are executed when the class is loading.
I just found out: -verbose:class shows all class loading events.
As Michael Borgwardt says, the simplest statement to achieve your aim is MyClass.class.
You might want to assign the value returned to something just in case the compiler ever decided that the statement had no side effects and could be optimized away, but I don't believe that any do.
Related
I have to admit that this is more a cosmetic issue, but the fact that I haven't found a more straight-forward solution makes me think I am probably missing something.
The thing is, my class (let's say Foo) has a very important static block where it registers itself (Foo.class) with a builder method in a Map, like this:
// somewhere in the class
static {
Bar.registerBuilder(Foo.class, Foo::build);
}
This makes it possibe to get a Foo builder from the Bar class, a bit like this:
// somewhere in a method
Foo foo = Bar.getBuilder(Foo.class).apply("Hello World");
(if the builder takes a String argument). However, the upper code example will only work if the Foo class was already initialized. If not, this means the static block of Foo wasn't executed and the builder isn't registered in Bar by now, which is leading to getBuilder() returning null and apply() throwing a NullPointerException.
Thanks to the internet (mostly StackOverflow) I found out that you can imperatively with Class.forName(String). But what really confuses me is that this method takes a String (therefore throws the checked ClassNotFoundException) and I haven't found a way to load and initialize a class directly via a java.lang.Class instance. I would have expected something like
Class<Foo> clazz = Foo.class;
clazz.load(); // does not exist
Instead I have to do this:
Class<Foo> clazz = Foo.class;
try {
Class.forName(clazz.getName());
} catch (ClassNotFoundException) {
// handle an exception that is actually unreachable
}
I would like to know if I am completely missing something, or if not, if there is a cleaner way to load and initialize a class via the java.lang.Class representation.
Any help is appreciated, thank you!
EDIT 1: As #Boris the Spider pointed out in the comments, Foo.class should probably already load and initialize the class, but it doesn't (in my case, at least) and that's why I even encountered this problem.
EDIT 2: Using the "complicated" way to load the class via Class.forName() (as in the code example) actually resolves the problem as I thought. It's just that I'd like to use a cleaner way if possible.
Using:
Java 11 (openjdk 11.0.2)
IntelliJ IDEA Ultimate (2019.3)
Maven (3.6.3)
If you are already referencing the class it would be much better to move that static code into normal static factory method. As why would you use reflections or try to reference some class just to make some code run when you can just run that method?
public static BuilderFunction createBuilder() {
return Foo::build;
}
And just call it in static block of Bar:
registerBuilder(Foo.class, Foo.createBuilder());
If you need something more dynamic you can use service loaders, especially with java 9+ as they are much nicer now to use:
provides my.BuilderProvder with something.FooProvider;
And just load them all in Bar:
ServiceLoader<BuilderProvder> loader = ServiceLoader.load(BuilderProvder.class);
loader.stream()
.forEach(provider -> registerBuilder(provider));
now even different modules not developed by you can provide own builders and you don't need to do any manual class loading (and class initialization is only guaranteed to happen if class is actually used, like some method or field used - note that constants are inlined at compilation so they don't count).
You can also use some hacky reflection libraries like ClassGraph or Reflections to get all classes of given type/with given annotation and then load them and invoke some init method on them all just like in my first proposed solution with createBuilder. This is how many components inside spring are registered, similar thing can be done with java annotation preprocessing to find this classes at compile time and just save the names. But if possible I would suggest sticking to existing build in solutions like service loaders.
I need to change existing compiled .class file. Actually I have even sources of it, but I cannot just change and recompile it because of many dependencies that I don't have.
So I need to change 2 methods. Both them have void return type. The first contains just 2 lines that are calls of another methods of the same class, i.e.
public void a() {
System.out.println("a");
}
public void b() {
System.out.println("b");
}
public void ca() {
a();
b();
}
And I need to change method ca sp that it calls only a() method.
The second method that I need to change contains some logic, but I want to clear it at all, i.e. to have method with empty body that does nothing.
How can I do this?
If you don't have the required dependencies, how are you expecting to use this code? I would strongly recommend that you devote your time to being able to compile this normally, instead of trying to just change the binary. It's likely to be a better bet in the long run.
I would take a look at AspectJ and set triggers to every call of ca. Then you can easily block that call and call a instead.
Try this question on Java Bytecode editors.
java bytecode editor?
However, I think Jon Skeet's answer is the one that really applies here.
I am not sure if you can change it in the first place, but even if you did succeed, I wouldn't recommend that. A cleaner solution would be to extend your class and override the implementation of the ca() method to call only the a() method.
If method a is public then the easiest way is to use an aspect (Aspect Oriented Programming, AspectJ) and intercept every call to ca. Instead of invoking ca just invoke a.
Have you tried looking into reflection? I have limited experience with it, but I'm not sure what you want to do it possible.
You can use Javaasist library to modify existing class file.
I had a similar problem.
I had to modify a method in a class file with no source.
The method was rethrowing the exceptions badly so I had to tweak it.
I have decompiled the class with Classfile Analyzer (http://classfileanalyzer.javaseiten.de/)
I have edited then the resulted file and recompiled it with Jasmine assembler.
Using Apache BCEL you can accomplish the same thing but in a more elegant way - at runtime - not as I have described above at compile time.
You can use a java decompiler for opening the class file and edit it and save it.
Here's one good decomp --> http://java.decompiler.free.fr/
Using reflection you can get pretty much everything relating to a class. You can get all the declared methods, fields and classes (and possibly even more), but i couldn't find a way to reflect on a method so i could find out what classes that method might be using.
Essentially i would like to find out all dependencies to other classes that a given class has.
Example:
Given the following code:
import com.yada.yada.yada.SomeClass
public class MyClass
{
public MyClass
{
new SomeClass();
}
}
How can i find out that MyClass is using SomeClass in its constructor?
I was trying to think of a way to get all import statements defined in a class file but i couldn't find anything that way either. But, assuming there's a way to somehow dig up all import statements defined in a class file, how would one find out about classes defined in the same package, which do not require an import statement?
EDIT:
Scenario: The goal is to send the bytecode of this class (MyClass) to another process. This other process then takes in the bytecode and loads the class (MyClass) using class loaders, and so on. The problem is that when i try to create and run an instance of MyClass in the other process it fails because it cannot find a definition for SomeClass.
If SomeClass were a member of MyClass it wouldn't be a problem but since the only reference to it lies in a method, there's no way to get to it via reflection?
I think the closest you can come to getting all of a class's dependencies is by hooking into the class loader mechanism and recording what classes get loaded when the class you're examining is instantiated and its methods are called. Of yourse, you'd transitively also get all the classes that it indirectly depends on, but depending on what you want to do with the information, that may be what you actually need.
But it's impossible to do for all cases (just imagine a method that uses Class.forName() to ask for a random class name every time it's called).
how would one find out about classes defined in the same package
That's actually impossible to do in general, since the class loader concept really only allows asking for a fully qualified class name, and either getting that class or a ClassNotFoundException. Classes can be loaded from a webserver (in the case of applets) or generated on the fly, so you cannot know whether a specific class exists except by asking for it.
You can't (unless you decompile the bytecode). A local variable is not tied to any class instance, and it does not even exist for most of the lifetime of the class or its instances, so you can't access it via reflection.
What are you trying to achieve? Maybe if you tell us about your actual problem, rather than a perceived solution, we are better able to help.
Reflection does not help you here. The only way I can think of that you can achieve this is through a byte code tool like asm.
Create a ClassVisitor that gathers dependencies from
Class declarations
Annotations
Local variable declarations
Field declarations
Method declarations
Method invocations
(have I forgotten anything?)
I have a class that calls a native function to get information about a system from its CMOS. The class has a static initialization block which loads the library containing the native function, and it looks something like this:
package lib.sysid;
public class SysId
{
private static native int getSysIdNative();
private static final String SYS_ID_PATH = "libsysid.so";
static
{
System.load(SYS_ID_PATH);
}
public static int getSysIdFromCMOS()
{
int returnValue = getSysIdNative();
}
}
According to my testing, the method works fine the first time I use it, but if I call the method again at a later time, the static initialization block also runs, causing an UnsatisfiedLinkError:
java.lang.UnsatisfiedLinkError: Native Library libsysid.so already loaded in another classloader
How can I avoid the static initialization block from executing the System.load() method if it has already been run?
Alternatively, is there a way for me to attempt to "unload" the library if it is already loaded before calling the System.load() method again?
EDIT: Strangely enough, if I surround the System.load() call with a try-catch block, I still get an UnsatisfiedLinkError, but this time it comes from the actual call to getSysIdNative(). The error I see is the following:
lib.sysid.SysId.getSysIdNative()I
What the heck is that "I" that shows up? I've tried to attach a debugger to this code to see where the message gets populated, but so far I haven't been successful.
Just a guess, but I think the only way for a single JVM to load a class (and execute its static initializers) twice is to load it with different classloaders. So there may be a second classloader involved here that you're not aware of. This would apply if a different (set of) classloader(s) is in effect the second time around.
Under a "real" operating system, java -verbose:class would give you loader messages to verify this with. I'm not sure how you'd go about verifying this on an embedded system. You could modify getSysId() to print (?) or somehow dump a reference to SysId.class.getClassLoader().
I think #Carl is right. The only way that a static initializer can run twice in a JVM is if the class is being loaded in multiple class loaders.
lib.sysid.SysId.getSysIdNative()I What the heck is that "I" that shows up?
That's easy. The I is based on the internal representation of types in signatures that is defined by the class file format. In particular, I means the primitive int type; see Class.getName(), etc. This matches your method's return type.
(It is a little bit confusing that these primitive type names show up in application space occasionally, but they do. Another case where you can see them is when you call toString() on a class that inherits the method implementation from the Object class.)
I am working on a project in which, to resolve a versioning issue, I am creating many classes which will never be tested and must not ever be used - they just need to be there to keep the compiler happy. I'd like to make sure they are never used. This morning I had the idea of throwing an exception in a static initialization block:
public class Dummy {
static {
throw new IllegalStateException("Do not use this class!");
}
}
But the compiler doesn't like it. Can you think of any way to do this?
EDIT: to be clear (my fault I wasn't clear before), these won't just be empty classes. There will be all sorts of code in here, and by "keep the compiler happy" I did indeed mean that elsewhere I will be instantiating them, calling methods etc etc. I want this code elsewhere to compile but fail at runtime. I have accepted Jon's answer but will also be using #Deprecated and documenting extensively as appropriate.
#Deprecated
A program element annotated #Deprecated is one that programmers are discouraged from using, typically because it is dangerous, or because a better alternative exists. Compilers warn when a deprecated program element is used or overridden in non-deprecated code.
Just add a dummy condition:
public class Dummy {
static {
if (true) {
throw new IllegalStateException("Do not use this class!");
}
}
}
I'm not really sure I like this, but it may do what you want it to. Are you sure there's no alternatively which would let you get away without having a completely useless class like this?
Give it a private default constructor, and make the class final.
Assuming you don't want IllegalStateExceptions potentially being thrown in your production code, use assertions and make sure they are enabled on your QA/Test environment. The code is slightly nicer too:
public class Dummy {
static {
//This class should never be initialised!
assert false : "This class should never be initialised";
}
...
}
You may get around the compiler with something like:
public class Dummy {
static {
if (true)
throw new IllegalStateException("Do not use this class!");
}
}
But that would be cheating ;-)
If they are never referenced, make the classes default scope, so no other types outside of the package can see them. If they can't see them they can't reference them (without using reflection that is).
class Dummy {
//no-op
}
Why don't you just not put that class into the jar that gets deployed. That way it'll be there at compile time but if someone tried to access it at runtime you'll get a ClassNotFoundException.
Use AssertionError instead of IllegalStateException
I don't think you can do that, though you can put a #deprecated tag before the class declaration. This way the compiler will give you a warning if you try to use it, but it will still compile.
You could use your own ClassLoader and check every class against a black list of classes.
What do you mean by "use"? If you need to have them in there, it sounds like the compiler needs to be able to create the classes. However, if you don't want any instances of the class to be created, then create an Assertion or throw an exception in the actual constructor.