List all interfaces in a package in a jar file - java

Hello stackoverflow'ers!
I am trying to list all classes from an interface in a specific package.
I came across multiple solutions and tried the following:
Using Reflections:
AllCommands = new ArrayList<ICommand>();
Reflections reflections = new Reflections(this.getClass().getPackage().getName());
commandClasses = reflections.getSubTypesOf(ICommand.class);
for (Class<? extends ICommand> c :commandClasses){
AllCommands.add((ICommand)c.newInstance());
}
Using extcos:
AllCommands = new ArrayList<ICommand>();
ComponentScanner scanner = new ComponentScanner();
scanner.getClasses(new ComponentQuery() {
#Override
protected void query() {
select().
from(this.getClass().getPackage().getName()).
andStore(thoseImplementing(ICommand.class).into(commandClasses)).
returning(none());
}
});
for (Class<? extends ICommand> c :commandClasses){
AllCommands.add((ICommand)c.newInstance());
}
Both solutions are successfully listing all my classes when debugging in NetBeans (7.3), but when i compile the jar and execute it, the commandClasses collections seems to stay empty. I am not used to java but i guess it has to do something with the classpath, and the debugging-time taking the classes from the \target\classes folder and not from the jar.
Can someone help me out with a solution that would allow me to list classes in the .jar?
Is it possible that this.getClass().getPackage().getName() just has to change to something that points into the jar?

I figured it out myself.. Using this.getClass().getPackage().getName() as Packagename does only point at the files in the classes folder, to reference classes in the jar i needed to replace the '.' to '/'. Thank you anyway.

Related

Why NoSuchMethodError in ant built jar?

I'm trying to make an Ant build script for my project, which runs fine in Eclipse. When I try to run the exported jar:
java -verbose:class -jar MyProject.jar
I get an unexpected error:
java.lang.NoSuchMethodError: com.employer.MyInterface.myMethod()I
what's really weird about this is debugging attempts like these all appear to be producing expected output (both before the export and after):
System.out.println("1:" + (myObj instanceof MyClass));
System.out.println("2:" + (myObj instanceof MyInterface));
Class c = MyClass.class;
URL myClassURL = c.getProtectionDomain().getCodeSource()
.getLocation();
System.out.println("url: " + myClassURL);
try {
Method[] m = c.getDeclaredMethods();
for (int i = 0; i < m.length; i++) {
System.out.println(m[i].toString());
}
} catch (Throwable e) {
System.err.println(e);
}
System.out.println("gni2:" + myObj.myMethod());
where MyClass implements MyInterface. That is, I can see both the interface and the class in my jar file if I examine it using emacs, I see the class loader load each of them, I see myMethod in getDeclaredMethods, there's only one MyClass.class in the jar, etc.
I've changed this to an Answer your own question because I figured it out while typing up the question. Instead of deleting the question, here's the solution just in case it helps someone else.
The problem ended up being that 2 of the projects that my project depends on have overlapping package+class names. I think a colleague copied code from one project to the other at some point in the past and then only maintained one of them. Eclipse uses the first class it finds based the order in a Build Path setting, whereas Ant overwrites one class with the other based on the order in the build file (and the orders end up being reversed).

Compiling a program inside of another program [to a jar file?] [duplicate]

I have the class name stored in a property file. I know that the classes store will implement IDynamicLoad. How do I instantiate the class dynamically?
Right now I have
Properties foo = new Properties();
foo.load(new FileInputStream(new File("ClassName.properties")));
String class_name = foo.getProperty("class","DefaultClass");
//IDynamicLoad newClass = Class.forName(class_name).newInstance();
Does the newInstance only load compiled .class files? How do I load a Java Class that is not compiled?
How do I load a Java Class that is not compiled?
You need to compile it first. This can be done programmatically with the javax.tools API. This only requires the JDK being installed at the local machine on top of JRE.
Here's a basic kickoff example (leaving obvious exception handling aside):
// Prepare source somehow.
String source = "package test; public class Test { static { System.out.println(\"hello\"); } public Test() { System.out.println(\"world\"); } }";
// Save source in .java file.
File root = new File("/java"); // On Windows running on C:\, this is C:\java.
File sourceFile = new File(root, "test/Test.java");
sourceFile.getParentFile().mkdirs();
Files.write(sourceFile.toPath(), source.getBytes(StandardCharsets.UTF_8));
// Compile source file.
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
compiler.run(null, null, null, sourceFile.getPath());
// Load and instantiate compiled class.
URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { root.toURI().toURL() });
Class<?> cls = Class.forName("test.Test", true, classLoader); // Should print "hello".
Object instance = cls.newInstance(); // Should print "world".
System.out.println(instance); // Should print "test.Test#hashcode".
Which yields like
hello
world
test.Test#ab853b
Further use would be more easy if those classes implements a certain interface which is already in the classpath.
SomeInterface instance = (SomeInterface) cls.newInstance();
Otherwise you need to involve the Reflection API to access and invoke the (unknown) methods/fields.
That said and unrelated to the actual problem:
properties.load(new FileInputStream(new File("ClassName.properties")));
Letting java.io.File rely on current working directory is recipe for portability trouble. Don't do that. Put that file in classpath and use ClassLoader#getResourceAsStream() with a classpath-relative path.
properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("ClassName.properties"));
In the same vein as BalusC's answer, but a bit more automatic wrapper is here in this piece of code from my kilim distribution.
https://github.com/kilim/kilim/blob/master/src/kilim/tools/Javac.java
It takes a list of strings containing Java source, extracts the package and public class/interface names and creates the corresponding directory/file hierarchy in a tmp directory. It then runs the java compiler on it, and returns a list of name,classfile pairs (the ClassInfo structure).
Help yourself to the code. It is MIT licensed.
Your commented code is correct if you know that the class has a public no-arg constructor. You just have to cast the result, as the compiler can't know that the class will in fact implement IDynamicLoad. So:
IDynamicLoad newClass = (IDynamicLoad) Class.forName(class_name).newInstance();
Of course the class has to be compiled and on the classpath for that to work.
If you are looking to dynamically compile a class from source code, that is a whole other kettle of fish.

How do I define a filtered FileTree using Gradle's Java API?

I am building a Gradle plugin in Java because of some Java libraries I want to take advantage of. As part of the plugin, I need to list and process folders of files. I can find many examples of how to do this in gradle build files:
FileTree tree = fileTree(dir: stagingDirName)
tree.include '**/*.md'
tree.each {File file ->
compileThis(file)
}
But how would do I do this in Java using Gradle's Java api?
The underlying FileTree Java class has very flexible input parameters, which makes it very powerful, but it's devilishly difficult to figure out what kind of input will actually work.
Here's how I did this in my java-based gradle task:
public class MyPluginTask extends DefaultTask {
#TaskAction
public void action() throws Exception {
// sourceDir can be a string or a File
File sourceDir = new File(getProject().getProjectDir(), "src/main/html");
// or:
//String sourceDir = "src/main/html";
ConfigurableFileTree cft = getProject().fileTree(sourceDir);
cft.include("**/*.html");
// Make sure we have some input. If not, throw an exception.
if (cft.isEmpty()) {
// Nothing to process. Input settings are probably bad. Warn user.
throw new Exception("Error: No processable files found in sourceDir: " +
sourceDir.getPath() );
}
Iterator<File> it = cft.iterator();
while (it.hasNext()){
File f = it.next();
System.out.println("File: "+f.getPath()"
}
}
}
It's virtually the same, e.g. project.fileTree(someMap). There's even an overload of the fileTree method that takes just the base dir (instead of a map). Instead of each you can use a for-each loop, instead of closures you can typically use anonymous inner classes implementing the Action interface (although fileTree seems to be missing these method overloads). The Gradle Build Language Reference has the details. PS: You can also take advantage of Java libraries from Groovy.

Building a ServiceLoader file with gradle: howto?

I am starting to switch from a well-known Java build system to Gradle to build all my projects, and after barely two hours into it I have already been able to publish a new version of one of my projects without a problem -- a breeze.
But now I encounter a difficulty. In short, I need to replicate the functionality of this Maven plugin which generates the necessary files for a ServiceLoader-enabled service.
In short: given a base class foo.bar.MyClass, it generates a file named META-INF/services/foo.bar.MyClass whose content is a set of classes in the current project which implement that interface/extend that base class. Such a file would look like:
com.mycompany.MyClassImpl
org.othercompany.MyClassImpl
In order to do this, it uses I don't know what as a classloader, loads the Class objects for com.myCompany.MyClassImpl or whatever and checks whether this class implements the wanted interface.
I am trying to do the same in Gradle. Hours of googling led me to this plugin, but after discussing with its author a little, it appears this plugin is able to merge such files, not create them. So, I have to do that myself...
And I am a real beginner both with Gradle and Groovy, which does not help! Here is my current code, link to the full build.gradle here; output (which I managed to get somehow; doesn't work from a clean dir) shown below (and please bear with me... I do Java, and I am final happy; Groovy is totally new to me):
/*
* TEST CODE
*/
final int CLASS_SUFFIX = ".class".length();
final URLClassLoader classLoader = this.class.classLoader;
// Where the classes are: OK
final File classesDir = sourceSets.main.output.classesDir;
final String basePath = classesDir.getCanonicalPath();
// Add them to the classloader: OK
classLoader.addURL(classesDir.toURI().toURL())
// Recurse over each file
classesDir.eachFileRecurse {
// You "return" from a closure, you do not "continue"...
if (!isPotentialClass(it))
return;
// Transform into a class name
final String path = it.getAbsolutePath();
final String name = path.substring(basePath.length() + 1);
final String className = name.substring(0, name.length() - CLASS_SUFFIX)
.replace('/', '.');
// Try and load it
try {
classLoader.loadClass(className);
println(className);
} catch (NoClassDefFoundError ignored) {
println("failed to load " + className + ": " + ignored);
}
}
boolean isPotentialClass(final File file)
{
return file.isFile() && file.name.endsWith(".class")
}
The output:
com.github.fge.msgsimple.InternalBundle
failed to load com.github.fge.msgsimple.bundle.MessageBundle: java.lang.NoClassDefFoundError: com/github/fge/Frozen
failed to load com.github.fge.msgsimple.bundle.MessageBundleBuilder: java.lang.NoClassDefFoundError: com/github/fge/Thawed
com.github.fge.msgsimple.bundle.PropertiesBundle$1
com.github.fge.msgsimple.bundle.PropertiesBundle
com.github.fge.msgsimple.provider.MessageSourceProvider
com.github.fge.msgsimple.provider.LoadingMessageSourceProvider$1
com.github.fge.msgsimple.provider.LoadingMessageSourceProvider$2
com.github.fge.msgsimple.provider.LoadingMessageSourceProvider$3
com.github.fge.msgsimple.provider.LoadingMessageSourceProvider$Builder
com.github.fge.msgsimple.provider.LoadingMessageSourceProvider
com.github.fge.msgsimple.provider.MessageSourceLoader
com.github.fge.msgsimple.provider.StaticMessageSourceProvider$Builder
com.github.fge.msgsimple.provider.StaticMessageSourceProvider$1
com.github.fge.msgsimple.provider.StaticMessageSourceProvider
com.github.fge.msgsimple.source.MessageSource
com.github.fge.msgsimple.source.MapMessageSource$Builder
com.github.fge.msgsimple.source.MapMessageSource$1
com.github.fge.msgsimple.source.MapMessageSource
com.github.fge.msgsimple.source.PropertiesMessageSource
com.github.fge.msgsimple.locale.LocaleUtils
com.github.fge.msgsimple.serviceloader.MessageBundleFactory
com.github.fge.msgsimple.serviceloader.MessageBundleProvider
:compileJava UP-TO-DATE
The problem is in the two first lines: Frozen and Thawed are in a different project, which is in the compile classpath but not in the classpath I managed to grab so far... As such, these classes cannot even load.
How do I modify that code so as to have the full compile classpath availabe? Is my first question. Second question: how do I plug that code, when it works, into the build process?
Here are some hints:
Create a new URLClassLoader, rather than reusing an existing one.
Initialize the class loader with sourceSets.main.compileClasspath (which is an Iterable<File>) rather than classesDir.
Turn the code into a Gradle task class. For more information, see "Writing a simple task class" in the Gradle User Guide.
Ideally, you'd use a library like ASM to analyze the code, rather than using a class loader. To avoid the case where you cannot load a class because it internally references a class that's not on the compile class path, you may want to initialize the class loader with sourceSets.main.runtimeClasspath instead.

how to make java use the newest version of a file

I have this problem that i have a program that writes and creates a .java file and puts it in my package folder, after this it takes the information from the .java file and uses it in it self. (it creates a new class with a method that i then import).
The problem is that if it wont work until i with eclipse update the "self created file". is there a way to make my main file update the "self created file".
Sorry if this is a duplicate. I just couldn't find it any where.
my code:
package dk.Nicolai.Bonde;
import java.io.*;
public class main {
public String outputString ="Math.sqrt(25)" ;
static String outputPath ="src/output.txt";
/**
* #param args
* #throws UnsupportedEncodingException
* #throws FileNotFoundException
*/
public static void main(String[] args) throws IOException{
new main().doit(args);
}
public void doit(String[] args) throws IOException{
PrintWriter writer = new PrintWriter("src/dk/Nicolai/Bonde/calculate.java", "UTF-8");
writer.println("package dk.Nicolai.Bonde;");
writer.println("public class calculate{");
writer.println("public void calc(){");
writer.println("System.out.println("+outputString+");");
writer.println("}");
writer.println("}");
writer.flush();
writer.close();
calculate calcObj = new calculate();
calcObj.calc();
}
}
Your main mistake is that you expected that it's during runtime automagically compiled into a .class file after save (which a sane IDE such as Eclipse is doing automatically for you behind the scenes everytime you press Ctrl+S). This is thus not true. During runtime, you need to compile it yourself by JavaCompiler and then load by URLClassLoader. A concrete example is given in this related question&answer: How do I programmatically compile and instantiate a Java class?
You'll in the concrete example also notice that you can't do just a new calculate(); thereafter. The classpath won't be auto-refreshed during runtime or so. You'd need to do a Class#forName(), passing the FQN and the URLClassLoader. E.g.
Calculate calculate = (Calculate) Class.forName("com.example.Calculate", true, classLoader);
Your other mistake is that you're relying on the disk file system's current working directory always being the Eclipse project's source root folder. This is not robust. This folder is not present at all when building and distributing the application. You should instead write the file to a fixed/absolute folder elsewhere outside the IDE project's structure. This is also covered in the aforelinked answer.
No, you cannot. You have to manually update resources in Eclipse. Although you can write a plugin for Eclipse which runs your file and update resources.
Eclipse uses directories and files to store its resources but is not direct representation of file system.
Your code could not work, because
calculate is required at compile time of main. You supply it at runtime.
calculate.java will not compiled, so even other techniques to dynamically load classes will not work
If you want to build classes at runtime, consider to use the reflexion API

Categories