getResources() returns an empty Enumeration - java

I'm using a util class (http://pastie.org/private/mxvpdrs3y2xutbjdo68a#11,14,17) to iterate over all classes inside a package.
The problem is that getResources("my/package") returns an empty Enumeration even though getResource("my/package/MyClass.class") gives the correct URL for all containing classes ("jar:file:/C:/Users/---/Desktop/Server/plugins/Test.jar!/my/package/MyClass.class").
Usage (in my.test.Reader):
List<Class<?>> classes = new ArrayList<Class<?>>();
try {
classes = new ClassScanner("my.package").scan();
} catch (ClassNotFoundException | IOException ex) {
ex.printStackTrace();
}
Debugging (in my.scan.ClassScanner): http://pastie.org/private/dhahvghtitqeiv6jex15q
Regards,
squibs

Related

Instantiate and use an object with only the textual class name in Java

I have several classes in the same package in Java. I want to instantiate objects of these classes from an array that has the class names as strings.
Here is an example of a class I would like to use, they all have the same structure.
class Class1 {
public String[] firstMethod(){
String[] data = {"NEW_ITEM"};
return data;
}
}
Here is the class I am attemtempting to instantiate them from.
class Main {
static {
String[] classes = {"Class1","Class2"};
for (String cls : classes) {
try {
Object o = Class.forName(cls).newInstance();
o.firstMethod();
} catch(ClassNotFoundException | IllegalAccessException | InstantiationException ex) {
System.out.println(ex.toString());
}
}
My problem is that when I try to call firstMethod() using the object o, I am getting this error.
exit status 1
Main.java:19: error: cannot find symbol
o.firstMethod();
^
symbol: method firstMethod()
location: variable o of type Object
1 error
I suspect that it is because it is of type Object and not type Class1. I have seen solutions where you typecast the object to the object of the class that you need. However when you typcast, you need to use the name of the class, which is exactly what I am trying to avoid. I need to use the class name as a string.
Does anyone know of a solution where I can call methods with the objects that are created?
You can't call your method the way in your code because you have an object which does not know the type Class1. You need to cast it explicitly like
((Class1)o).firstMethod()
which I don't think this is what you want.
Or, you can iterate through object methods and invoke it dynamically like below:
String[] classes = {"com.yourpackage.Class1", "com.yourpackage.Class2"};
for (String cls : classes) {
try {
Object o = Class.forName(cls).newInstance();
for(Method m : o.getClass().getMethods()) {
System.out.println(m.getName());
if ("firstMethod".equals(m.getName())) {
String[] data = (String[])m.invoke(o, null); // here are the parameters
for(String d : data){
System.out.println(d);
}
}
}
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException ex) {
System.out.println(ex.toString());
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
The output is :
NEW_ITEM

Unable to use #spring annotations when class object is new

Actually i am having a spring main class as follows.
ClassLoader loader = null;
try {
loader = URLClassLoader.newInstance(new URL[]{new
File(plugins + "/" + pluginName + "/" + pluginName +
".jar").toURI().toURL()}, getClass().getClassLoader());
} catch (MalformedURLException e) {
e.printStackTrace();
}
Class<?> clazz = null;
try {
clazz = Class.forName("com.sample.Specific", true, loader);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Method method = null;
try {
method = clazz.getMethod("run",new Class[]{});
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
try {
method.invoke(clazz.newinstance,new Object[]{});
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
Specific Class is follow :
package com.sample
#Service
public class Specific {
#Autowired
private FD fd;
public void run(){
fd.init();
}
}
#Autowired FD comes to be null. Can anyone give me some solution as i also know new operator will not work for #autowired. As i am loading class with new instance then only it becomes null. Can anyone guide me in this thing
Spring has its own way to provide you new objects. As long as you're consistent using #Autowired and #Component/#Service/#Repository/#Controller there should be no problem
And since all "business" object instantiation is handled by Spring you should never use new. If you have no other way of getting an instance (something I realy doubt about it) you can use ApplicationContext.getBean() but as I said, in most cases this is not required (and this is also a bad practice)
If you need several instances of a class instead of injecting them (by using #Autowired) you can inject a Provider<T>
UPDATE
Since the class is known at runtime you need to inject an ApplicationContext and use it to get the bean:
public class TheClassWhereYouAreCreatingTheObject {
#Autowired
private ApplicationContext context; // You definitely need this
public void theMethodWhereYouAreCreatingTheObject() {
Class<?> clazz = ... // getting the object class
Object instance = context.getBean(clazz); // getting and instance trough Spring
// If you know that kind of object you will get cast it at call its methods
((Specific) instance).run();
// If you know anything about the class you will have to use reflection
Method method = clazz.getMethod("run", new Class[]{});
method.invoke(instance, new Object[]{});
}
}
Add Specific Service bean inside your main class. As long as the service is inside one your component scan packages then you shall be fine. Do not use new operator.
#Autowired
private Specific specific;
If you want to take advantage of autowiring then I think we have to think from spring terms.
you can use Beanutils to create a new instance and play with reflections supporting spring features.
Please go through below methods:
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/beans/BeanUtils.html

Java dynamic loading a class issue

I am trying to write a code that compiles and runs another java class, after it creates it from a String.
My problem is when I run
Class classToLoad = null;
ClassLoader classLoader = Server.class.getClassLoader();
try {
classToLoad = classLoader.loadClass(className);
} catch (Exception e) {
e.printStackTrace();
}
It throws a ClassNotFoundException. My problem isn't about the package, because if I debug the code and place a breakpoint before the "getClassLoader" and I reload the classes, then my code works fine and it sees the class that was recently created earlier in the app.
How can I reload the classes during runtime so the loadClass will work?
Take a look at this tutorial:
ClassLoader Load / Reload Example
... Let's look at a simple
example. Below is an example of a simple ClassLoader subclass. Notice
how it delegates class loading to its parent except for the one class
it is intended to be able to reload. If the loading of this class is
delegated to the parent class loader, it cannot be reloaded later.
Remember, a class can only be loaded once by the same ClassLoader
instance.
As said earlier, this is just an example that serves to show you the
basics of a ClassLoader's behaviour. It is not a production ready
template for your own class loaders. Your own class loaders should
probably not be limited to a single class, but a collection of classes
that you know you will need to reload. In addition, you should
probably not hardcode the class paths either.
public class MyClassLoader extends ClassLoader{
public MyClassLoader(ClassLoader parent) {
super(parent);
}
public Class loadClass(String name) throws ClassNotFoundException {
if(!"reflection.MyObject".equals(name))
return super.loadClass(name);
try {
String url = "file:C:/data/projects/tutorials/web/WEB-INF/" +
"classes/reflection/MyObject.class";
URL myUrl = new URL(url);
URLConnection connection = myUrl.openConnection();
InputStream input = connection.getInputStream();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int data = input.read();
while(data != -1){
buffer.write(data);
data = input.read();
}
input.close();
byte[] classData = buffer.toByteArray();
return defineClass("reflection.MyObject",
classData, 0, classData.length);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
Below is an example use of the MyClassLoader.
public static void main(String[] args) throws
ClassNotFoundException,
IllegalAccessException,
InstantiationException {
ClassLoader parentClassLoader = MyClassLoader.class.getClassLoader();
MyClassLoader classLoader = new MyClassLoader(parentClassLoader);
Class myObjectClass = classLoader.loadClass("reflection.MyObject");
AnInterface2 object1 =
(AnInterface2) myObjectClass.newInstance();
MyObjectSuperClass object2 =
(MyObjectSuperClass) myObjectClass.newInstance();
//create new class loader so classes can be reloaded.
classLoader = new MyClassLoader(parentClassLoader);
myObjectClass = classLoader.loadClass("reflection.MyObject");
object1 = (AnInterface2) myObjectClass.newInstance();
object2 = (MyObjectSuperClass) myObjectClass.newInstance();
}
Probably asking: "What is the context in which you are loading the class?" will help answer your question better.
Most standard frameworks like Spring handle loading classes internally and exposing only the methods that those classes provide.
Try Class.forName(String name) to attempt to load the class and return the handle to the class object.
If you want to specifically use your own classloader to load the class, use the overloaded: Class.forName(String name, boolean initialize, ClassLoader loader)
But you will need to ensure that your classloader is able to locate the class to load correctly.
For the classloader you are using, try:
Thread.currentThread().getContextClassLoader()

Cannot get JAXBContext?

In my java project i have a jar that i generated with some classes. I am able to instantiate the instance of the class that is in my jar:
Alert a = new Alert();
But wen i try to do this:
JAXBContext context = JAXBContext.newInstance(Alert.class);
I get run time exception like this:
java.lang.InternalError:
Error occured while invoking reflection on target classes. Make sure all referenced classes are on classpath: interface javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter
Exception: null
Any idea what could be the issue?
Thank you
This happened to me as I had defined XmlAdapter implementations that were in a different JAR and not on the classpath. When trying to create the JAXBContext, it needs these adapters used by the JAXB type. Now that I figured this out, the message makes more sense, but is still very cryptic. XmlJavaTypeAdapter is the annotation interface and the code fails to call the value() method of the annotation as it returns Class<? extends XmlAdapter>, a class type which is not defined on the classpath.
If you look at the code that throws the exception, this is impossible:
public Class More ...getClassValue(Annotation a, String name) {
try {
return (Class)a.annotationType().getMethod(name).invoke(a);
} catch (IllegalAccessException e) {
// impossible
throw new IllegalAccessError(e.getMessage());
} catch (InvocationTargetException e) {
// impossible
throw new InternalError(e.getMessage());
} catch (NoSuchMethodException e) {
throw new NoSuchMethodError(e.getMessage());
}
}
Would be nice if the cause of the exception was not lost.

Load a class from a jar

I´m trying to load a class from a jar, I´m using a classLoader.
I have this parts of code for prepare the classLoader:
private void loadClass(){
try{
JarFile jarFile = new JarFile( Path);
Enumeration e = jarFile.entries();
URL[] urls = { new URL("jar:file:" + Path +"!/") };
classLoader = URLClassLoader.newInstance(urls);
} catch (MalformedURLException ex) {
// TODO Auto-generated catch block
ex.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Now I load a class, and I try to get a new instance
....
loadClass();
Class device = classLoader.loadClass( "org.myPackage.MyClass");
MyMotherClass Device = ( MyMotherClass) device.newInstance();
...
MyClass extends of MyMotherClass, and when I do classLoader.loadClass( "org.myPackage.MyClass"), the MyMotherClass it is in the classLoader.
At the moment, all right.
now, in device.newInstance(), I get a exception. The problem is the other classes that are used by MyClass, are not in the classpath.
What can i do?
I have a another method that load all the needed classes in the classLoader, but does not work when I get the new instance.
I can not change MyClass and the others
Here's some code I use to load a jar dynamically at run-time. I exploit reflection to circumvent the fact that you ain't really supposed to do this (that is, modify the class path after the JVM has started). Just change my.proprietary.exception to something sensible.
/*
* Adds the supplied library to java.class.path.
* This is benign if the library is already loaded.
*/
public static synchronized void loadLibrary(java.io.File jar) throws my.proprietary.exception
{
try {
/*We are using reflection here to circumvent encapsulation; addURL is not public*/
java.net.URLClassLoader loader = (java.net.URLClassLoader)ClassLoader.getSystemClassLoader();
java.net.URL url = jar.toURI().toURL();
/*Disallow if already loaded*/
for (java.net.URL it : java.util.Arrays.asList(loader.getURLs())){
if (it.equals(url)){
return;
}
}
java.lang.reflect.Method method = java.net.URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{java.net.URL.class});
method.setAccessible(true); /*promote the method to public access*/
method.invoke(loader, new Object[]{url});
} catch (final NoSuchMethodException |
java.lang.IllegalAccessException |
java.net.MalformedURLException |
java.lang.reflect.InvocationTargetException e){
throw new my.proprietary.exception(e.getMessage());
}
}

Categories

Resources