Enforcing loading a class at program start in java - java

Is there a way to enforcing loading a class after programm start? I have following case: I have a hashmap holding Name and java.lang.Class of plugin classes. in each plugin class I have a static block registring the class
static {
ClassMap.getInstance().register("name",MyPlugin.class);
}
I don't know the name and package of in this example MyPlugin. So I want that this code will executed at programm start. How is this possible?

If the class object is in the map, this means that the class has already been loaded i.e. your static block has been executed already.
If on the other hand, you just have the class names (e.g. in a list) you can do his:
for(String classname : yourList){
// wrap with try / catch
Class.forName(className);
}
Here is a pretty good overview of what happens at class load time
Update: what you seem to want is a kind of component scanning that will find all you plugin classes. There's no way to do that with plain Java, but you can e.g. use the reflections library to do that. Sample code:
Reflections reflections = new Reflections("com.your.project");
Set<Class<? extends YourBaseClass>> subTypes =
// and all of these classes are already initialized
reflections.getSubTypesOf(YourBaseClass.class);

Related

how to register a java class if the static initializer isn't called till the class is referenced

I've an interface implemented by classes that perform a file processing, say searching or whatever.
public interface FileProcessorInterface {
public void processFile(String fileName);
}
Then i have a different implementation for each file type:
public class TxtProcessor implements FileProcessorInterface {
#Override public void processFile(String fileName) { //do the work }
}
Thus i have the Utilizer of the processor, that has a method that allows for registering each class, something like this:
class Utilizer {
Map <String, Class> registered = new HashMap<>();
public void registerClass(String fileExt, Class clazz) {
registered.put(fileExt, clazz);
}
public void processFile(String fileName) {
//1) get the registered class from registered map (omitted because easy and not relevant)
//2) create an instance of the class using reflection (omitted because easy and not relevant)
FileProcessorInterface p = ....
p.processFile(fileName);
}
So far it's ok.
Now, i'm providing many implementations of my interface.
And i am tempted to provide each implementation class with a static initializer that register itself in the Utilizer, in the case of my previous TxtProcessor it would be:
class TxtProcessor implements FileProcessorInterface {
//previous code
static {
Utilizer.registerClass("txt", TxtProcessor.class);
}
}
The problem is that this static method will never be called because in the "statically reachable" code of the application there is no reference to my TxtProcessor class, since it is instantiated via reflection. So the jvm does not call the static initializer.
Say that i have two parts: the "generic code" that is the Utilizer and on the other side the implementations; it has to be thought as something provided dinamically and so it is not known by the Utilizer part.
Infact the idea was exactly that each class would register itself leaving the Utilizer untouched.
It is hard for me conceiving a solution that does not put some form of 'knowledge' of the implementations on the Utilizer side (and that stays simple), just because of the problem of the static initializer not called. How to overcome this?
Using reflections seems to be the best fit here. It's like geared to do this.
All you need is a small static block in Utilizer as
static {
Reflections reflections = new Reflections(
new ConfigurationBuilder()
.setUrls(ClasspathHelper.forPackage("path.to.all.processors.pkg"))
.setScanners(new SubTypesScanner())
);
reflections.getSubTypesOf(path.to.all.processors.pkg.FileProcessor.class);
}
If you don't want a third-part dependency, just add a FileProcessors.properties file to your classpath
txt=path.to.all.processors.pkg.TxtProcessor
doc=path.to.all.processors.pkg.DocProcessor
pdf=path.to.all.processors.pkg.PdfProcessor
and then register all the listed classes from Utilizer as
static {
Properties processors = new Properties();
try {
processors.load(Utilizer.class
.getResourceAsStream("FileProcessors.properties"));
} catch (IOException e) {
e.printStackTrace();
}
for (String ext : processors.stringPropertyNames()) {
Utilizer.registerClass(ext, Class.forName(processors.getProperty(ext));
}
}
This no longer requires a static block in every FileProcessor now.
You can look at Reflections library. It allow you to find all the classes which implement an interface, have an annotation or extend a class.
You Could...
Use the same concept as JDBC does for loading it's drivers. This would require you to use Class#forName to initialize the class when the program is first loaded. While this does mean that the implementation is still dynamic from the point of view of your utility class, it is specified at run time by your application...
This gives you control over which implementation you might want to use
You Could...
Use the same concept as something like java.awt.Toolkit uses when it initializes it's instance.
It basically looks up the resource (in this case a System property) and then loads the class dynamically using Class.
Personally, I normally look for a named resource (usually a properties file) and load a key from it.
Something like getClass().getResource("/some/gloabl/configFile");, which every implementation would need to provide.
Then, if available, read the properties file and find the key I'm after.
If more then one implementation is linked in though, there is no guarantee which one will be loaded.
Quick and dirty: You can statically initialize your Utilizer in main() with correct association.
Better solution: externalize in a resource file association like
txt=path.to.package.TxProcessor
load it in Utilizer and load FileProcessorInterface implementors with Class.forName()
you can force the static init by Class.forName(fqn, true, classLoader) or the short form Class.forName(fqn)
You could have a registry file (for example, some XML file), that would contain the list of all classes you support :
<item type="txt">somepackage.TxtProcessor</item>
<item type="gif">somepackage.GIFProcessor</item>
...
Your Utilizer would load this file into its registry.

instantiating a Scala class using reflection Java's `newInstance`

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
}

Reflections could not get class type

I am using a third party library called Reflections (not to be mistaken with Java reflection) to search another jar for Classes that extend Foo using the following code:
Reflections reflections = new Reflections("com.example");
for(Class<? extends Foo> e : reflections.getSubTypesOf(Foo.class)) {
doSomething()
}
When I do this Reflections throws the following error:
org.reflections.ReflectionsException: could not get type for name com.example.ExtendsFoo
Does anyone know how to fix this cause I'm stumped?
Thanks in advance!
The problem may be due to not having a class loader that can resolve the name (even though it can resolve the subtype). This sounds contradictory, but I had the error message when I was building a Configuration and using ClasspathHelper.forClassLoader on an application- instantiated URLClassloader to figure out what to scan on the classpath, but not passing in said URLClassLoader into the Reflections configuration so that it could instantiate things correctly.
So you may want to try something along the lines of the following:
URLClassLoader urlcl = new URLClassLoader(urls);
Reflections reflections = new Reflections(
new ConfigurationBuilder().setUrls(
ClasspathHelper.forClassLoader(urlcl)
).addClassLoader(urlcl)
);
where urls is an array of URLS to the jars containing the classes you want to load. I was getting the same error as you if I did not have the final addClassLoader(...) call to the ConfigurationBuilder.
If this doesn't work, or is not applicable, it may be worth just setting a breakpoint in ReflectionsUtil.forName(String typeName, ClassLoader... classLoaders)) to see what is going on.
Take a look: https://code.google.com/p/reflections/issues/detail?id=163
Reflections (in its current version 0.9.9-RC1) doesn't re-throw exception correctly. That's why you may miss the true cause of the problem. In my case it was a broken .class file, which my default class loader failed to load and threw an exception. So, first of all, try to make sure that your class is truly loadable.
Scanning for classes is not easy with pure Java.
The spring framework offers a class called ClassPathScanningCandidateComponentProvider that can do what you need. The following example would find all subclasses of MyClass in the package org.example.package
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(true);
provider.addIncludeFilter(new AssignableTypeFilter(MyClass.class));
// scan in org.example.package
Set<BeanDefinition> components = provider.findCandidateComponents("org/example/package");
for (BeanDefinition component : components)
{
This method has the additional benefit of using a bytecode analyzer to find the candidates which means it will not load all classes it scans.
Class cls = Class.forName(component.getBeanClassName());
// use class cls found
}
Fore more info read the link

attempting to get class names from a different package

Have got two projects javaapplication2 and javaapplication1. The same being their package names. In javaapplication2 ive imported javaapplication1 using
import javaapplication1.*;
i need to list all classses in the packeage. How to achieve this? I tried a simple code but it gets a null exception.
Package pck;
pck = Package.getPackage("javaapplication1");
System.out.println(pck.getClass());
I don't have enough rep to comment on this question or to mark it as such, but it is a duplicate of:
Getting all Classes from a Package
There are many good answers listed on that question - for instance the top is looking for classes that implement ICommand, so to implement this all you need to do is remove:
if (ICommand.class.isAssignableFrom(cls)) {
commands.add((Class<ICommand>) cls);
}
from the for loop and you have what you want.
I guess the jar containing package javaapplication1 is not in classpath as
Package.getPackage("javaapplication1");
is returning null for you.
Also,
You can have a look at the following link:
http://dzone.com/snippets/get-all-classes-within-package
or can explore the Reflection library from Google in order to get the required information, below is a sample code.
e.g.
Reflections reflections = new Reflections("javaapplication1");
Set<Class<? extends Object>> allClasses = reflections.getSubTypesOf(Object.class);
If you go throgh the object class API it is written as:
//Object API
getClass
public final Class getClass()Returns the runtime class of an object. That Class object is the object that is locked by static synchronized methods of the represented class.
Returns:
the object of type Class that represents the runtime class of the object.
It's clearly written as it represents the run time class of an object.
Suppose if you have class called as "Helloworld" in side "javaapplication1" package
create object of the class as:
Helloworld world=new Helloworld();
and then try to run as
System.out.println(wolrld.getClass());
It will return the class path of current object.

can't cast to implemented interface

i'm very confused...
I have a class which directly implements an interface:
public class Device implements AutocompleteResult
{...}
Here is proof that I'm looking at the right variables:
Object match = ...;
log.debug(match.getClass()); // Outputs 'Device'
log.debug(match.getClass().getInterfaces()[0]); // Outputs 'AutocompleteResult'
Yet when I try to cast an instance of the class to the interface:
AutocompleteResult result = (AutocompleteResult) match;
I get a ClassCastException!
ClassCastException: Device cannot be cast to AutocompleteResult
Also, isAssignableFrom returns false and i'm not sure why:
log.debug(AutocompleteResult.class.isAssignableFrom(Device.class));
from the doc:
Determines if the class or interface represented by this Class object is either the same as, or is a superclass or superinterface of, the class or interface represented by the specified Class parameter.
Shouldn't I always be able to cast a object to an interface its class implements?
Thanks.
This can happen if two different classloaders load a class named AutocompleteResult.
These two classes are then treated as entirely different classes, even if they have the same package and name (and even implementation/fields/methods).
A common cause for this is if you use some kind of plugin system and both your base classes and the plugin classes provide the same class.
To check for this issue print the value returned by Class.getClassLoader() on both offending classes (i.e. the class of the interface implemented by Device and the result of AutocompleteResult.class).
AKA when Java apparently doesn't Java.
I hit this problem recently with Play Framework 2.6.3, what helped me was this:
https://www.playframework.com/documentation/2.6.x/ThreadPools#Application-class-loader
I leave this info here for the people that might have the same problem.
To make it clearer, what helps is:
Injecting Application on an Eager Singleton and then using its classloader to load the classes I was having issues with.
To make it clearer
public class Module {
#Override
public void configure {
bind(TheClassLoaderLoader.class).asEagerSingleton()
public static class TheClassLoaderLoader {
#Inject
public TheClassLoaderLoader( Application application) {
ClassLoader classloader = application.classloader();
Class<?> interfaceClass = classloader.loadClass(InterfaceClass.class.getName());
classloader.loadClass(ImplementsInterfaceClass.class.getName()).asSubclass(interfaceClass);
The example here https://playframework.com/documentation/2.6.x/JavaDependencyInjection#Configurable-bindings
That uses Environment often throws a frustrating ClassNotFoundException
Cheers

Categories