Load external java function through XQuery with Saxon - java

I can access Java class and methods when executing xquery with Saxon when they are declared correctly (through namespace pointing to package and class) but I wonder if there is a way to create a kind of "dynamic" class path at each run to load external jar file and search classes in it instead of in the current project/program classpath (as I cannot add all possible class in it).
So for instance I have something like :
declare namespace dpr="java:com.*****.atm.dpr.common.util.DPRConfigurationLoader";
declare variable $rules as node()* := doc(dpr:getApplicationProperty('Common','RulesFileLocation'))//category;
I can replace the path the real class with an emulated version but it means I must create each possible class on my side (not really a good way as it means a "patch" for each new java call...).
So if I provide a jar containing the classes I need is there a way to load it so that the namespace point to it ?
I know I can load .class file if they are on classpath, but 3 jar files entirely ?
Thanks.

Technically, Saxon doesn't require external classes to be on the classpath - it requires them to be accessible using the appropriate ClassLoader. If you understand ClassLoaders and are prepared to write your own or configure third-party offerings, then you can load classes from anywhere. All the hooks are there in Saxon if you want to do such things; but there's nothing packaged with the product.
Some of the thing you could try include:
With Configuration.setDynamicLoader() you can change the way Saxon does dynamic loading of external classes, including the classes used for Java extension functions.
With Configuration.getDynamicLoader().setClassLoader() you could provide a different ClassLoader for loading classes, for example a URLClassLoader.
With ProfessionalConfiguration.setExtensionBinder("java", XXX) you could register a customized JavaExtensionLibrary, typically as a subclass of the standard one, allowing you to change the way URIs are mapped to Java classes and the way methods are selected (for example)
This is all very low-level system programming and is not for the faint-hearted.

Related

Is there a way to inspect class, field and method level annotations in an "unloaded" java class file?

I would like to inspect annotations present in a java class file without requiring any of it's dependedencies to be loaded, only requiring the loading of the basic JVM libraries and the class file in question only.
To load a class at runtime in java requires a classpath having it's field, method, and parameter dependencies findable. I want to do this in an environment where non of those other files may exist.
Is this possible? is there an available library to do this?
Simple: then you do not want to load the class.
You consider the class as a class file living in the file system.
In other words: it is a resource containing binary data - which you then parse. Either yourself, or by using a library that does that for you (which would be the sane, preferred way instead of re-inventing the wheel).
See here for a list of options how to do that. Or you directly turn to the asm byte code parser.
You don't need any external library, just use java.lang.Class. Write the name of your class:
[NameOfMyClass].class.getDeclaredFields();
[NameOfMyClass].class.getDeclaredConstructors();
[NameOfMyClass].class.getDeclaredMethods();
It's the same for interfaces and many other attributes.

How to manage JARs with third-party implementations in configuration classes?

Assume that
I like to manage the configuration of a Java application in form of one or many classes referencing each other which I de/serialize to/from XML because I like the way how that saves a lot of work.
I have a Java project with interfaces and the application packaged in different JARs where interfaces are designed to allow third-parties to implement interfaces and the user to load them at runtime through a fancy GUI. Configuration classes exist in form of interfaces and thus can occur in the serialized XML.
I would like to have one configuration file only controlling all pathes of all resources (I'll probably have to give that up, but I'm curious about your answers). It is searched for in a default location and created with default values if inexisting or can be specified on command line.
How would I go about getting the information about the location of third-party implementations before loading the configuration and still keep one clean configuration file only?
I
parse the XML once using XStream and XStream.omitField for the field which contains instances of configuration classes which need to be loaded from a referenced JAR.
Then I read the partial configuration to the location of the JARs and load the classes.
Then I overwrite the partially parsed configuration with a completely deserialized one (using a new instance of XStream).

How to scan for a particular annotation of java classes loaded at runtime as a bytecode?

If a java class loaded at runtime as a bytecode (e.g. via ASM library or other mechanism), is it on a classpath of java? I don't see it.
How to scan all annotations of classes loaded this way, if it's not on the java classpath?
I use google reflections and a custom classloader of a 3-rd party library.
Scanning for classes works as follows:
Reflections reflections = new Reflections(ClasspathHelper.forPackage("com.mypackage",
MyCustomClassLoader),
new SubTypesScanner(), new TypeAnnotationsScanner());
Set<Class<?>> myClasses = reflections.getTypesAnnotatedWith(MyAnnotation.class);
MyAnnotation - is marked as #Retention(RetentionPolicy.RUNTIME).
The above (in a class) is loaded dynamically at runtime by JVM.
As can be seen, behind the scenes, Reflections tries to get all URLs to be scanned using 2 classloaders by default static and context.
Reflection.scan()
Update: I have found an answer Can you find all classes in a package using reflection? saying that "If there are classes that get generated, or delivered remotely, you will not be able to discover those classes." But there is no proof, however.
Can please anybody give more details on this and confirm?
Dynamically instantiating classes at run time does not change the classpath that your JVM is using. What happens is that some ClassLoader class fetches bytecode from somewhere; and makes it "available" to you. But that does in no way change the "search order" for loading classes (and that is basically what the classpath is about: it only tells the JVM where and in which order to look for classes to load).
Meaning: any "loading" of a class results in some object of class java.lang.Class.
If you want to query the structure of any loaded class; you "just" need to get to the corresponding Class object. Class provides methods like getAnnotation(). It also provides methods to retrieve other objects that represent the methods and fields of the specific Class; and those objects can be queried for annotations in similar ways.
Update, regarding the updates in the question: there are situations where you don't have access to the file system where classes are coming from. You can load classes, when you know their name, but you have no way looking into the "place" where these classes live. And that basically breaks your ability to use reflection as intended.
There is no need to "prove" that, it is simply a consequence of the fact that Java allows you to load classes when you know there name, but "hides" the exact content of "where" those classes are coming from.

Is there a way to unpack jars in runtime and access methods of classes?

This might be a little vague but I wanted to know if I have a class name (including the package) before hand, say in a file and I have a bunch of jars in the classpaths. Then is there a way I can look into a particular jar to find that class and access some method from that class?
What I am actually trying to do is to load some values from different class, dynamically. If the above approach is flawed then is there any other way to do it? Am not completely certain about how the class loader works, so I didn't want to go down that rabbit hole just yet.
EDIT An abstract example of what am trying to do:
I have a program that builds a graph for me using certain information, for the purpose of this example lets say that information is alphabets. I have some jars in my classpath that have a class that has a method that returns these alphabets for that specific class. Now I got the order of the classes I need to build the graph from, so if I am able to extract these alphabets from the jars, I can build my graph.
You can use a URLClassLoader and its methods to find classes in a .jar file (typically) once you have the Class object, you can use java.lang.reflect to instantiate objects, call methods, or inspect variables
If the jars are your own: Consider using java.util.ServiceLoader. It helps to find any classes residing on the classpath at runtime that implement a given Interface, as long as you declare them in a META-INF/services list.
So you let the classloader load the classes without knowing their names and simply call their methods.
I'm not sure if there is a clean way to find out (enumerate) the names of all classes only by reflection without scanning the jars as a zip.

How can I enumerate all child classes of a superclass in Java

My application consists of several JAR files. I would like to iterate over all of the JAR files and find all classes that subclass a particular class, so that I can cause their static initializers to run.
I looked though the Javadocs for java.lang.ClassLoader, but can't find any method that does this.
I am trying to implement the "Product Trader" pattern (http://www.ubilab.com/publications/print_versions/pdf/plop-96-producttrader.pdf), with the classes "self-registering" in the abstract superclass. The superclass will have a HashMap that maps the service a subclass provides and the java.lang.Class file that handles that service.
The problem is that a class does not run it's static initializers until it is loaded. If I can iterate all of the subclasses, I can force each to load and run it's initializers.
Thanks, Ralph
This is not generally solvable. A ClassLoader is not required to be able to iterate over the Classes it could load. The easiest example of a ClassLoader that can't do that is when you load classes from a http:// base URL: HTTP provides no standardized way to enumerate the content of any given URL.
An better way to implement this is to use the ServiceLoader and let all implementing classes register themselves via a simple entry in their jar file.
This is obviously not solvable very simply.
However, there are solutions, like the one mentionned in this Javaworld article.
Generally speaking, it consists into exploration all elements from the CLASSPATH. if they're jar files, explore them looking for classes, load those classes and see if they extend you reference base class.
However, i would strongly suggest you use a more "mature" mechanism like IoC or a plugin architecture.
I'm obviously thinking about JSPF, as an example.
If you really need to do this the only real way is to iterate through the classpath, scanning the jars and directories for class files, loading that class and looking at it's parent class.
Note, some classes will have static initialising code that can have bad side affects, e.g. loading X11 classes from the runtime can hang for a long long time. If possible try to restrict what classes you load to specific packages, e.g. com.company (you can of course identify the package by the path of the class file relative to the root to the classpath item).
[Note the ServiceLoader suggested by Joachim Sauer, or a framework that provides a similar mechanism is a much better solution]

Categories

Resources