How to instantiate .class file which i get at run time - java

I get a class file at runtime and I am saving it in a particular location. How can I create an object of this class:
Class.forName(MyDynamicClass);
This does not work. The class does not have any package, so how to instantiate this class ?
I just have the MyDynamicClass.class file which is in my home folder
I tried "Amir Afghani" answer which throws the ClassNotFound Exception.

Steps that you can try to debug:
Check your class path
When you perform Class.forName("MyDynamicClass");
It checks in your classpath for the file MyDynamicClass.class and loads it
When you run your program, run with -verbose argument
This will help you identify how this class is searched and is loaded once you fix the class path issue
If you do not want to add this to your classpath, then you will most definitely have to write your own class loader (See java.net.URLClassLoader which provides an easier way to do this). This will allow you to put custom paths to be loaded

I have tested with and without package and both cases working fine.
Below are the classes
Default Package:
public class MyDynamicClass {
}
Under package com.test
package com.test;
public class MyDynamicClass {
}
package com.test;
public class MyDynamicClassTest {
public static void main(String[] args) {
try {
Class clazz = Class.forName("com.test.MyDynamicClass");
Class clazz2 = Class.forName("MyDynamicClass");
System.out.println("clazz :: "+ clazz);
System.out.println("clazz :: "+ clazz2);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
Output:
clazz :: class com.test.MyDynamicClass
clazz :: class MyDynamicClass
You can call newInstance() to create object once you have class object.
How are you compiling your class? Can you make sure there is .class file exist?

ClassLoader myClassLoader = ClassLoader.getSystemClassLoader();
// Step 2: Define a class to be loaded.
String classNameToBeLoaded = "MyDynamicClass";
// Step 3: Load the class
Class myClass = myClassLoader.loadClass(classNameToBeLoaded);
// Step 4: create a new instance of that class
Object whatInstance = myClass.newInstance();

Related

How to determine if a class exists in the project

I have to make a program in which I input a class name and the program returns a true/false value if it is present in the project or not.
The idea is that the program scans all the directories of the project src. I have heard that it is possible to do this with the Reflection API, but I have no clue on how to do it?
Use the class loader. Any class that is reachable from the same class loader as "FindClass" can be found. Remember to use the class's package name as part of the name: "package.class".
public class FindClass {
public boolean findClass(String className) {
try {
FindClass.class.getClassLoader().loadClass(className);
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
An alternative to using the above classloader is to use the class loader that loaded the application.
Thread.currentThread().getContextClassLoader().loadClass(className);

Is it possible to change buggy class in a closed source library that was not built to support dependency injection?

Say I am using a closed source java library with a known buggy class, say BuggyClass and this class is hardcoded throughout the rest of the library. So I would imagine that the java library looks something like this:
public class BuggyClass {
public T buggyMethod (...) {
// Buggy code here
}
}
with several other classes in the library that make use of this class:
public class Example {
private BuggyClass = new BuggyClass(); // No dependency injection possible
public Example (/* No way to pass in my own subclass of BuggyClass*/) {
// ...
}
}
etc...
Is there any hack, or workaround, possibly using the class loader so that I could subclass BuggyClass and get Example (and every other class in the library that has BuggyClass hardcoded in) to use my subclass?
You can't do a subclass, no, but you can write your own BuggyClass entirely and make sure it appears earlier in the classpath than the real one. I don't think it's documented, but the default classloader seems to typically use the first matching class it finds.
But obviously this is a Really Bad Option, so you want to exhaust every other avenue before trying to solve temporarily work around the underlying problem this way.
Example: Suppose we have this:
// The "buggy" class
package somepackage;
public class BuggyClass {
public String someMethod() {
return "I'm in the buggy class";
}
}
and this:
// Uses the "buggy" class
package somepackage;
public class BuggyClassUser {
public String useBuggyClass() {
BuggyClass c = new BuggyClass();
return c.someMethod();
}
}
compiled and the classes in buggy.jar. Then we have this test class:
import somepackage.*;
public class Test {
public static final void main(String[] args) {
BuggyClassUser u = new BuggyClassUser();
System.out.println(u.useBuggyClass());
}
}
If we run that (*nix format classpath):
java -cp .:buggy.jar Test
...we see
I'm in the buggy class
But if we create a somepackage directory and put this in it:
package somepackage;
public class BuggyClass {
public String someMethod() {
return "I'm in the fixed class"; // <== Difference here
}
}
...and compile that, since we have that in our classpath in front of the jar, this command:
java -cp .:buggy.jar Test
...now gives us this:
I'm in the fixed class
Again, this is very, very much a workaround, not a solution.

Extending class with only private constructors

The problem is: I have a class with only private constructor available (and I cannot modify it's source code), and I need to extend it.
Since reflections allow us to create instances of such classes whenever we want (with getting constructors and calling for newInstance()), is there any way to create an instance of an extended version of such class (I mean, really any way, even if it is against OOP)?
I know, it is a bad practice, but looks like I have no choice: I need to intercept some calls to one class (it is a singleton, and it's not an interface realization, so dynamic proxies do not work here).
Minimal example (as requested):
public class Singleton {
static private Singleton instance;
private Singleton() {
}
public static Singleton getFactory() {
if (instance == null)
instance = new Singleton();
return instance;
}
public void doWork(String arg) {
System.out.println(arg);
}}
all I want to do is to construct my own wrapper (like this one)
class Extension extends Singleton {
#Override
public void doWork(String arg) {
super.doWork("Processed: " + arg);
}}
and the inject it into Factory using reflection:
Singleton.class.getField("instance").set(null, new Extension());
But I do not see any way to construct such object cause its superclass's constructor is private. The question is "is that possible at all".
It is possible (but a bad hack) if
you have the source code of the class with the private constructors or you can reconstitute it from bytecode
the class is loaded by the application class loader
you can modify the jvm's classpath
You can than create a patch that is binary compatible with the original class.
I will call the class you want to extend PrivateConstructorClass in the following section.
Take the source code of PrivateConstructorClass and copy it to a source file. The package and class name must not be changed.
Change the constructors of the PrivateConstructorClass from private to protected.
Re-compile the modified source file of PrivateConstructorClass.
Package the compiled class file into a jar archive. E.g. called "patch.jar"
Create a class that extends the first one and compile it against the class in the patch.jar
Change the jvm's classpath so that the patch.jar is the first entry in the classpath.
Now some example code that let you examine how it works:
Expect the following folder structure
+-- workspace
+- private
+- patch
+- client
Create the PrivateConstructor class in the private folder
public class PrivateConstructor {
private String test;
private PrivateConstructor(String test){
this.test = test;
}
#Override
public String toString() {
return test;
}
}
Open a command prompt in the private folder, compile and package it.
$ javac PrivateConstructor.java
$ jar cvf private.jar PrivateConstructor.class
Now create the patch file in the patch folder:
public class PrivateConstructor {
private String test;
protected PrivateConstructor(String test){
this.test = test;
}
#Override
public String toString() {
return test;
}
}
Compile and package it
$ javac PrivateConstructor.java
$ jar cvf patch.jar PrivateConstructor.class
Now comes the interresting part.
Create a class that extends the PrivateConstructor in the client folder.
public class ExtendedPrivateConstructor extends PrivateConstructor {
public ExtendedPrivateConstructor(String test){
super(test);
}
}
and a main class to test it
public class Main {
public static void main(String str[]) {
PrivateConstructor privateConstructor = new ExtendedPrivateConstructor("Gotcha");
System.out.println(privateConstructor);
}
}
Now compile the client folder's source files against the patch.jar
$ javac -cp ..\patch\patch.jar ExtendedPrivateConstructor.java Main.java
and now run it with both jars on the classpath and see what happens.
If the patch.jar comes before the private.jar than the PrivateConstructor class is loaded from the patch.jar, because the application class loader is a URLClassLoader.
$ java -cp .;..\patch\patch.jar;..\private\private.jar Main // This works
$ java -cp .;..\private\private.jar;..\patch\patch.jar Main // This will fail
The solution by #René Link was good enough, but not in my case: I wrote I'm hacking an Eclipse IDE plugin, and this means we're working under OSGi, and this means we cannot control the classpath resolving order (it will load our "hacked" class in our bundle, and vanilla victim class in another bundle, and it will do this with different classloaders, and then we would have problems with casting such objects one to another). Possibly OSGi has some tools to solve this problems, but I don't know it well enough, and also I found no info on this.
So we invented another solution. It is worse than previous one, but at least it works in our case (and so it's more flexible).
The solution is simple: javaagent. It's a standard tool, which allows to manipulate bytecode at the time it is loaded. So the task was solved by using it and java ASM library: the victim's bytecode was modified to make it's constructor public, the remaining was easy.
public class MyAgent {
public static void premain(String agentArguments, Instrumentation instrumentation) {
instrumentation.addTransformer(new ClassFileTransformer() {
#Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer)
throws IllegalClassFormatException {
if (className.equals("org/victim/PrivateClass")) { //name of class you want to modify
try {
ClassReader cr = new ClassReader(classfileBuffer);
ClassNode cn = new ClassNode();
cr.accept(cn, 0);
for (Object methodInst : cn.methods) {
MethodNode method = (MethodNode) methodInst;
if (method.name.equals("<init>") && method.desc.equals("()V")) { //we get constructor with no arguments, you can filter whatever you want
method.access &= ~Opcodes.ACC_PRIVATE;
method.access |= Opcodes.ACC_PUBLIC; //removed "private" flag, set "public" flag
}
}
ClassWriter result = new ClassWriter(0);
cn.accept(result);
return result.toByteArray();
} catch (Throwable e) {
return null; //or you can somehow log failure here
}
}
return null;
}
});
}
}
Next this javaagent must be activated with JVM flag, and then everything just works: now you can have subclasses which can call super() constructor without any problem. Or this can blow your whole leg off.
EDIT: This clearly doesn't work with the newly posted code examples edited into the question above, but I will keep the answer here for future posterity should it help someone else.
One method available to you which may or may not work depending on your situation is to use the Delegation pattern. For example:
public class PrivateClass {
private PrivateClass instance = new PrivateClass();
private PrivateClass() {/*You can't subclass me!*/
public static PrivateClass getInstance() { return instance; }
public void doSomething() {}
}
public class WrapperClass {
private PrivateClass privateInstance = PrivateClass.getInstance();
public void doSomething() {
//your additional logic here
privateInstance.doSomething();
}
}
You now have a class, WrapperClass, which has the same API as PrivateClass but delegates all the functionality to PrivateClass (after doing some pre or post work itself). Obviously, WrapperClass is not associated with the type heirarchy of PrivateClass but can be setup to do everything PrivateClass can.

Java ClassLoader change

I have some class A:
public class A {
public A(String str) {
System.out.println("Create A instance: " + str);
}
public void methodA() {
System.out.println("#methodA1()");
}
}
And my class loader implementation:
public class MyClassLoader extends ClassLoader {
public MyClassLoader() {
super();
}
#Override
public synchronized Class<?> loadClass(String name)
throws ClassNotFoundException {
System.out.println("Load: " + name);
return super.loadClass(name);
}
}
And now I try to change default class loader in current thread:
import java.util.ArrayList;
import java.util.List;
public class ChangeLoaderTest {
public static void main(String[] args) {
// Save class loader so that we can restore later.
ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();
MyClassLoader newLoader = new MyClassLoader();
try {
// Set new classloader.
Thread.currentThread().setContextClassLoader(newLoader);
// My class.
A a = new A("1");
a.methodA();
// Standard Java class.
List<Integer> list = new ArrayList<Integer>();
list.add(2);
list.add(3);
} finally {
// Restore.
Thread.currentThread().setContextClassLoader(oldLoader);
}
}
}
And ChangeLoaderTest output:
Create A instance: 1
#methodA1()
No one
Load: ...
Why? How I can change ClassLoader into some thread?
As Marko Topolnik points out the context classloader is for use by frameworks. To use the classloader yourself you have to call loadClass("somepackage.A") and then use the reflection API to create a new instance of A (Class.newInstance()).
You wont be able to use A or its methods in your source directly since the calling code does not know A - it uses a different classloader. An interface or baseclass of A that can be loaded by the normal classloader can be used to avoid reflection.
interface AIF{
void someMethod();
}
class A implements AIF{
public void someMethod(){}
}
public void test(){
MyLoader loader = new MyLoader();
Class cla = loader.loadClass("A");
AIF a = (AIF) cla.newInstance();
a.someMethod();
}
The contextClassLoader mechanisms is not used by the basic Java operations like new. It's only there so various frameworks can access the context class loader in charge and load resources, classes, etc. Java will always use the classloader that loaded the code that is executing. It's the one that you access via ChangeLoaderTest.class.getClassLoader() -- and there is nothing you can do about this one.
I think that what happens is that your application's class loader which is also your classloader's "parent" can locate A and load it. As a result your classloader will not be searched or used for loading A.
To be honest, I haven't much experience with classloaders but if you subclassed one that uses a URL for the path of the class (so that it can locate the class file) and the parent classloader can not load it (not part of classpath), your custom one will be used.

How to access java classes in a subfolder

I'm trying to make a program that can load an unknown set of plugins from a sub-folder, "Plugins". All of these plugins implement the same interface. What I need to know is how do I find all of the classes in this folder so that I can instantiate and use them?
MyInterface.java
A stub interface.
package test;
public interface MyInterface {
public void printSomething();
}
TestClass.java
A test class to be loaded, implementing your interface.
import test.MyInterface;
public class TestClass implements MyInterface {
public void printSomething() {
System.out.println("Hello World, from TestClass");
}
}
(Compiled class file placed in "subfolder/".)
Test.java
A complete test program that loads all class files from "subfolder/" and instantiates and runs the interface method on it.
package test;
import java.io.File;
public class Test {
public static void main(String[] args) {
try {
ClassLoader cl = ClassLoader.getSystemClassLoader();
File subfolder = new File("subfolder");
for (File f : subfolder.listFiles()) {
String s = f.getName();
System.out.println("Loading " + s);
Class cls = cl.loadClass(s.substring(0, s.lastIndexOf('.')));
MyInterface o = (MyInterface) cls.newInstance();
o.printSomething();
}
} catch (ClassNotFoundException e) {
} catch (InstantiationException e) {
} catch (IllegalAccessException e) {
}
}
}
Output from Test program above:
Loading TestClass.class
Hello World, from TestClass
Check java.util.ServiceLoader
A service is a well-known set of interfaces and (usually abstract) classes. A service provider is a specific implementation of a service. The classes in a provider typically implement the interfaces and subclass the classes defined in the service itself. Service providers can be installed in an implementation of the Java platform in the form of extensions, that is, jar files placed into any of the usual extension directories. Providers can also be made available by adding them to the application's class path or by some other platform-specific means.
This article explains the details.
Look through the folder with File.listFiles() and use a JarClassLoader instance to load the classes in there.
Or, add a description.xml in each of those jars if they are on the classpath, and use getClass().getClassLoader().findResources("description.xml") to load all descriptions, and then you have all the plugin classes to load.
Annotate your implementation classes with a custom annotation and use scannotation it does byte code scanning of the class files, and is orders of magnitudes faster than anything else, you can use it to search the entirety of a very large classpath instantly.

Categories