I have an interface named Operator the directory of this interface is d:\operators
Interface definition is like so :
package operators;
public interface Operator
{
double calculate(double firstNumber,double secondNumber);
String getSign();
}
In the main program (d:\ProjectFile94.6.7\main) I want load this interface and use it .I load interface like so :
String rootPath = System.getProperty("user.dir")+System.getProperty("file.separator");
String operatorsPath = rootPath.replace("ProjectFile94.6.7" , "").replace("main" , "") + "operators";
System.out.println(operatorsPath);
//Load operators from another file
File operatorFile = new File(operatorsPath);
URL operatorFilePath = operatorFile.toURL();
URL[] operatorFilePaths = new URL[]{operatorFilePath};
ClassLoader operatorsLoader = new URLClassLoader(operatorFilePaths);
Class operatorInterface = operatorsLoader.loadClass("operators.Operator");
The app compiled fine but at runtime I got this exception :
java.lang.ClassNotFoundException : operators.Operator
You must not append the package name in the classpath directory:
String operatorsPath = rootPath.replace("ProjectFile94.6.7" , "").replace("main" , "");
i.e. the directory path should be just D:/. Otherwise, you're just telling the classloader to search for D:/operators/operators/Operator.class.
Related
I have written a simple Plugin system so that I can include extensions from external sources. The Plugin Manager loads plugins from predetermined application and user plugins directories. I use a custom URLClassLoader so that I can sandbox all Plugins. Here's the general approach:
Locate the Plugin's JAR file in one of the predetermined directories.
If the Plugin has already been loaded, return the instance of the Plugin that has already been created.
If an instance of the custom URLClassLoader has not been created for the directory containing the Plugin, create one.
Loop through each class in the Plugin's JAR file looking for Classes that implement the PluginInterface by loading the Class using Class.forName( pluginName, false, PluginClassLoader ) and then testing to see if the PluginInterface isAssignableFrom the loaded Class.
If the Class implements the PluginInterface then a new instance of the Class is created, initialized, and saved for later use.
All of this works great when I run it from within the Eclipse IDE. But, when I run it outside of the IDE, the check to see if the Plugin implements the PluginInterface fails. I believe this is because under Eclipse, both the Plugin and the Interface have a related (parent or child) ClassLoader (namely sun.misc.Launcher$AppClassLoader#73d16e93) and outside of Eclipse the PluginInterface has an unrelated ClassLoader (namely java.net.URLClassLoader#14ae5a5).
Here's the code:
The custom ClassLoader:
public class PROD_PluginClassLoader extends URLClassLoader {
protected PROD_PluginClassLoader( URL pluginFileUrl ) {
super( new URL[] { pluginFileUrl } );
}
protected PROD_PluginClassLoader( String pluginFilePath ) throws MalformedURLException {
super( new URL[] { new File( pluginFilePath ).toURI().toURL() } );
}
protected PROD_PluginClassLoader( URL[] pluginFileUrls ) {
super( pluginFileUrls );
}
}
The PluginLoader:
private static List< String > loadedPlugins = new ArrayList<>();
private static List< PROD_PluginInterface > plugins = new ArrayList<>();
private static Map< String, PROD_PluginClassLoader > pluginClassLoaders = new HashMap<>();
protected static void getPluginInstance( String pluginName, String pluginFilePath ) {
try {
PROD_Utilities.printDebug( "Loading plugin name(" + pluginName + ") from(" + pluginFilePath + ")" );
if ( !pluginClassLoaders.containsKey( pluginFilePath ) ) pluginClassLoaders.put( pluginFilePath, new PROD_PluginClassLoader( pluginFilePath ) );
PROD_PluginClassLoader pLoader = pluginClassLoaders.get( pluginFilePath );
boolean pluginLoaded = false;
for ( String n : PROD_Utilities.getClassNamesFromJarFile( pluginFilePath ) ) {
Class<?> pClass = Class.forName( n, false, pLoader );
String interfaces = "";
for ( Class<?> c : pClass.getInterfaces() ) interfaces += "," + c.getName();
if ( !interfaces.isEmpty() ) interfaces = interfaces.substring( 1 );
PROD_Utilities.printDebug( String.format( "Plugin name(%s) object class(%s) super(%s) interfaces(%s) isPlugin(%b)", pluginName, pClass.getName(), pClass.getSuperclass().getName(), interfaces, PROD_PluginInterface.class.isAssignableFrom( pClass ) ) );
if ( pClass.getInterfaces().length > 0 )
PROD_Utilities.printDebug(
String.format(
"pClass loader(%s) parent(%s) pClass interface loader(%s) parent(%s) PROD_PluginInterface loader(%s) parent(%s)"
,pClass.getClassLoader()
,pClass.getClassLoader().getParent()
,pClass.getInterfaces()[0].getClassLoader()
,pClass.getInterfaces()[0].getClassLoader().getParent()
,PROD_PluginInterface.class.getClassLoader()
,PROD_PluginInterface.class.getClassLoader().getParent()
));
if ( PROD_PluginInterface.class.isAssignableFrom( pClass ) ) {
Class<? extends PROD_Plugin> newClass = pClass.asSubclass( PROD_Plugin.class );
Constructor<?> constructor = newClass.getConstructor();
setPluginSandbox();
plugins.add( ( PROD_PluginInterface ) constructor.newInstance() );
plugins.get( plugins.size()-1 ).pluginInitialization();
unsetPluginSandbox();
pluginLoaded = true;
}
}
if ( pluginLoaded ) loadedPlugins.add( pluginName.toLowerCase() );
else PROD_Utilities.printError( "Plugin (" + pluginName + ") is not a valid PROD plugin." );
} catch ( InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException | ClassNotFoundException | NoSuchMethodException
| SecurityException | MalformedURLException e ) {
PROD_Utilities.printError( "Could not load plugin (" + pluginName + ").", e.getMesprod() );
}
}
The debug information when running under Eclipse:
Debug: PROD_PluginManager.getPluginInstance().line(138): Loading plugin name(proddb) from(C:\Users\userid\eclipse-workspace\prod\plugins\proddb.jar)
Debug: PROD_PluginManager.getPluginInstance().line(147): Plugin name(proddb) object class(com.company.prod.proddb.PRODDB) super(com.company.prod.PROD_Plugin) interfaces(com.company.prod.PROD_PluginInterface) isPlugin(true)
Debug: PROD_PluginManager.getPluginInstance().line(149): pClass loader(com.company.prod.PROD_PluginClassLoader#5ec0a365) parent(sun.misc.Launcher$AppClassLoader#73d16e93) pClass interface loader(sun.misc.Launcher$AppClassLoader#73d16e93) parent(sun.misc.Launcher$ExtClassLoader#55f96302) PROD_PluginInterface loader(sun.misc.Launcher$AppClassLoader#73d16e93) parent(sun.misc.Launcher$ExtClassLoader#55f96302)
The debug information when running outside of Eclipse:
Debug: PROD_PluginManager.getPluginInstance().line(138): Loading plugin name(proddb) from(C:\Users\userid\eclipse-workspace\prod\plugins\proddb.jar)
Debug: PROD_PluginManager.getPluginInstance().line(147): Plugin name(proddb) object class(com.company.prod.proddb.PRODDB) super(com.company.prod.PROD_Plugin) interfaces(com.company.prod.PROD_PluginInterface) isPlugin(false)
Debug: PROD_PluginManager.getPluginInstance().line(149): pClass loader(com.company.prod.PROD_PluginClassLoader#12405818) parent(sun.misc.Launcher$AppClassLoader#55f96302) pClass interface loader(sun.misc.Launcher$AppClassLoader#55f96302) parent(sun.misc.Launcher$ExtClassLoader#3d3fcdb0) PROD_PluginInterface loader(java.net.URLClassLoader#14ae5a5) parent(null)
I find it very strange that the PluginInterface ClassLoader has changed to a URLClassLoader.
I believe the problem is that the PluginInterface and the Plugin don't share a related ClassLoader and thus the Plugin's PluginInterface is technically a different Java interface from the Application's PluginInterface. If that assessment is correct then my question is how do I fix this so that the PluginInterface and the Plugin do share a related ClassLoader?
Or, perhaps my assessment is incorrect. In which case, my question is why doesn't the Plugin appear to implement the PluginInterface?
I've been wrestling with this for several days now so thanks in advance for any and all answers.
Edit
How is my code (not the plugin) loaded?
From within Eclipse: using the Eclipse Run -> Run menu option.
From outside of Eclipse: java -jar prod.jar
Well after a VERY long time, I finally figured this out and am posting my findings here in case anyone else runs across a similar issue with isAssignableFrom.
When exporting the program from Eclipse using the Export Wizard for Java->Runable JAR file, I chose Library handling option Package required libraries into generated JAR and was getting the isAssignableFrom failure as described in the original post. After re-exporting using Library handling option Extract required libraries into generated JAR, everything worked as expected.
I have taken a written sample from this link to write my Python + Java integration code.
http://www.jython.org/jythonbook/en/1.0/JythonAndJavaIntegration.html
The code looks like below.
package org.jython.book.interfaces;
import org.jython.book.interfaces.JythonObjectFactory;
import org.python.core.Py;
import org.python.core.PyString;
import org.python.core.PySystemState;
public class Main {
public static void main(String args[]) {
String projDir = System.getProperty("user.dir");
String rootPath = projDir + "/src/org/jython/book/interfaces/";
String modulesDir = projDir + "/src/org/jython/book/interfaces/";
System.out.println("Project dir: " + projDir);
PySystemState sysSt = Py.getSystemState();
JythonObjectFactory factory = new JythonObjectFactory(sysSt, BuildingType.class, "Building", "Building");
BuildingType building = (BuildingType) factory.createObject();
building.setBuildingName("BUIDING-A");
building.setBuildingAddress("100 MAIN ST.");
building.setBuildingId(1);
System.out.println(building.getBuildingId() + " " +
building.getBuildingName() + " " +
building.getBuildingAddress());
}
}
When I run this code, it throws an error that it did not find the python module. I have kept the .py and .pyc files under the path provided as 'modulesDir'.
The literature says that "the requested module must be contained somewhere on the sys.path"; however, I did not understand how this can be set from this Java program. Can someone please provide some help?
Project dir: /Users/eclipsews/PythonJava
Exception in thread "main" ImportError: No module named Building
Hi found the answer to this issue!
Added the PySystemState.initialize method where I explicitly provide the "python.path" property, which is initialized to my project's path, where python modules are available.
private static Properties setDefaultPythonPath(Properties props) {
String pythonPathProp = props.getProperty("python.path");
String new_value;
if (pythonPathProp == null) {
new_value = System.getProperty("user.dir") + "/src/org/jython/book/interfaces/";
}
props.setProperty("python.path", new_value);
return props;
}
Properties props = setDefaultPythonPath(System.getProperties());
PySystemState.initialize( System.getProperties(), props, null );
This produces the correct output as follows:
module=<module 'Building' from '/Users/eclipsews/PythonJava/src/org/jython/book/interfaces/Building$py.class'>,class=<class 'Building.Buildin
g'>
1 BUIDING-A 100 MAIN ST.
When using a directory-expression for an <int-file:outbound-gateway> endpoint, the method below is called on org.springframework.integration.file.FileWritingMessageHandler:
private File evaluateDestinationDirectoryExpression(Message<?> message) {
final File destinationDirectory;
final Object destinationDirectoryToUse = this.destinationDirectoryExpression.getValue(
this.evaluationContext, message);
if (destinationDirectoryToUse == null) {
throw new IllegalStateException(String.format("The provided " +
"destinationDirectoryExpression (%s) must not resolve to null.",
this.destinationDirectoryExpression.getExpressionString()));
}
else if (destinationDirectoryToUse instanceof String) {
final String destinationDirectoryPath = (String) destinationDirectoryToUse;
Assert.hasText(destinationDirectoryPath, String.format(
"Unable to resolve destination directory name for the provided Expression '%s'.",
this.destinationDirectoryExpression.getExpressionString()));
destinationDirectory = new File(destinationDirectoryPath);
}
else if (destinationDirectoryToUse instanceof File) {
destinationDirectory = (File) destinationDirectoryToUse;
} else {
throw new IllegalStateException(String.format("The provided " +
"destinationDirectoryExpression (%s) must be of type " +
"java.io.File or be a String.", this.destinationDirectoryExpression.getExpressionString()));
}
validateDestinationDirectory(destinationDirectory, this.autoCreateDirectory);
return destinationDirectory;
}
Based on this code I see that if the directory to use evaluates to a String, it uses that String to create a new java.io.File object.
Is there a reason that a ResourceLoader couldn't/shouldn't be used instead of directly creating a new file?
I ask because my expression was evaluating to a String of the form 'file://path/to/file/' which of course is an invalid path for the java.io.File(String) constructor. I had assumed that Spring would treat the String the same way as it treats the directory attribute on <int-file:outbound-gateway> and pass it through a ResourceLoader.
Excerpt from my configuration file:
<int-file:outbound-gateway
request-channel="inputChannel"
reply-channel="updateTable"
directory-expression="
'${baseDirectory}'
+
T(java.text.MessageFormat).format('${dynamicPathPattern}', headers['Id'])
"
filename-generator-expression="headers.filename"
delete-source-files="true"/>
Where baseDirectory is a property that changes per-environment of the form 'file://hostname/some/path/'
There's no particular reason that this is the case, it probably just wasn't considered at the time of implementation.
The request sounds reasonable to me and will benefit others (even though you have found a work-around), by providing simpler syntax. Please open an 'Improvement' JIRA issue; thanks.
While not directly answering the question, I wanted to post the workaround that I used.
In my XML configuration, I changed the directory-expression to evaluate to a file through the DefaultResourceLoader instead of a String.
So this is what my new configuration looked like:
<int-file:outbound-gateway
request-channel="inputChannel"
reply-channel="updateTable"
directory-expression=" new org.springframework.core.io.DefaultResourceLoader().getResource(
'${baseDirectory}'
+
T(java.text.MessageFormat).format('${dynamicPathPattern}', headers['Id'])).getFile()
"
filename-generator-expression="headers.filename"
delete-source-files="true"/>
I am using Weka to create a classifier via the Java API.
The instances are created using java code.
The classifier is being created from code as well via passing following
String args[]=" -x 10 -s 1 -W weka.classifiers.functions.Logistic".split(" ");
String classname;
String[] tmpOptions = Utils.splitOptions(Utils.getOption("W", args));
classname = tmpOptions[0];
System.out.println(classname);
Classifier cls = (Classifier) Utils.forName(Classifier.class, classname, tmpOptions);
It works fine and does cross validation.
After that I once again load my training instances and label their output as ?
and pass it to classifier using
for (int index = 0; index < postDatas.size(); index++) {
Instance instance = nominal.instance(index);
double label = classifier.classifyInstance(instance);
System.out.println(label);
}
classifier.classifyInstance(instance); gives me following exception:
java.lang.NullPointerException
at weka.classifiers.functions.Logistic.distributionForInstance(Logistic.java:710)
any clues to where am I going wrong?
Since you didn't provide all relevant information, I'll take a shot in the dark:
I'm assuming that you're using Weka version 3.7.5 and I found the following source code for Logistic.java online
public double [] distributionForInstance(Instance instance) throws Exception {
// line 710
m_ReplaceMissingValues.input(instance);
instance = m_ReplaceMissingValues.output();
...
}
Assuming you didn't pass null for instance, this only leaves m_ReplaceMissingValues. That member is initialized when the method Logistic.buildClassifier(Instances train)is called:
public void buildClassifier(Instances train) throws Exception {
...
// missing values
m_ReplaceMissingValues = new ReplaceMissingValues();
m_ReplaceMissingValues.setInputFormat(train);
train = Filter.useFilter(train, m_ReplaceMissingValues);
...
}
It looks like you've never trained your classifier Logistic on any data after you created the object in the line
Classifier cls = (Classifier) Utils.forName(Classifier.class, classname, tmpOptions);
I have developed a DSL with xText and recently add somme enhanced completion.
In a xText-generated editor when calling completion by Ctrl-Space, the completion handler has to perform a folder scanning to look for symbols in another text file of the same DSL.
The entry point is :
public class TypesProposalProvider extends AbstractTypesProposalProvider
{
public void completeQualifiedName_Path(
EObject model,
Assignment assignment,
ContentAssistContext context,
ICompletionProposalAcceptor acceptor )
{
super.completeQualifiedName_Path( model, assignment, context, acceptor );
I use:
Model root = (Model) context.getRootModel();
Resource rootRc = root.eResource();
to obtain the emf.ecore container of the model.
And now, how can I look for sibling resources, the other files in the same folder, in term of ecore resource?
With the another resources, I'll call Resource.load() to populate the underlaying emf.ecore model of the siblings.
I hope you understand my approximative English (I'm French)...
I am assuming that the sibling models dont refer each other. In that case you can use WorkspaceSynchronizer to get the file from the resource.
Example
Resource rootRc = root.eResource();
IFile file = WorkspaceSynchronizer.getFile(rootRc);
IResource parent = file.getParent();
Iresource[] childern = parent.members();
for(<iterate over children>)
load the children resources.
Hope this helps.
Here is the final version, compact as usual ;-) :
Resource rootRc = root.eResource();
String rcPath = rootRc.getURI().toPlatformString( true );
IFile file = (IFile)ResourcesPlugin.getWorkspace().getRoot().findMember( rcPath );
IContainer parent = file.getParent();
for( IResource member : parent.members())
{
String ext = member.getFileExtension();
if( ext != null && ext.equals( "types" ))
{
String prefix = member.getName();
String path = member.getLocation().toString();
URI uriSibling = URI.createFileURI( path );
prefix = prefix.substring( 0, prefix.length() - ".types".length());
if( ! rcPath.endsWith( '/' + prefix + ".types" )
&& ( context.getPrefix().isEmpty() || prefix.startsWith( cntxtPrefix )))
{
Resource types = rs.createResource( uriSibling );
types.load( null );
for( EObject rc : types.getContents())
{
...
}
}
}
}