Here is a running example of my DLLService :
import com.sun.jna.Native;
import com.sun.jna.win32.StdCallLibrary;
public class DLLService {
public DLLService() throws Exception {
System.out.println("version = " + version() + "\n");
testEvaluate();
}
public void testEvaluate() {
System.out.println(this.loadFile("file", 1));
int[] barre = new int[] {0, 1, 2, 3, 4};
int[] result = new int[]{};
evaluateParty(barre.length, barre, result, 1);
System.out.println(result);
}
public int version() {
return GDLL.INSTANCE.LireNoVersion();
}
public int loadFile(String tslName, int pdwNoSess) {
return GDLL.INSTANCE.ChargerFichier();
}
public interface GDLL extends StdCallLibrary {
GDLL INSTANCE = (GDLL) Native.loadLibrary("tsr32_mini", GDLL.class);
int LireNoVersion();
int ChargerFichier();
}
}
There is no problem with the function version() but not with the loadFile(...), I have the exception :
Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up function 'EvaluerPartie':
at com.sun.jna.Function.(Function.java:212) at
com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:541) at
com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:518) at
com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:504) at
com.sun.jna.Library$Handler.invoke(Library.java:220) at
com.sun.proxy.$Proxy0.EvaluerPartie(Unknown Source) at
DLLService.evaluateParty(DLLService.java:29) at
DLLService.testEvaluate(DLLService.java:16) at
DLLService.(DLLService.java:9) at
ProblemsIsolator.main(ProblemsIsolator.java:53)
I already search but found nothing that work (changing types, arguments, names, ...). Here is the prototype of the function l: DWORD ChargerFichier (LPSTR chNom, DWORD *pdwNoSess).
EDIT :
Same error, even after using a name mapper; it works for the LireVersion only :
public void testFunctionMapper() throws Exception {
FunctionMapper mapper = StdCallLibrary.FUNCTION_MAPPER;
NativeLibrary lib = NativeLibrary.getInstance("tsr32_mini");
Method[] methods = {
GDLL.class.getMethod("LireNoVersion",
new Class[] { String.class, int.class }),
GDLL.class.getMethod("ChargerFichier",
new Class[] { String.class, int.class }),
};
for (int i=0;i < methods.length;i++) {
String name = mapper.getFunctionName(lib, methods[i]);
lib.getFunction(name, StdCallLibrary.STDCALL_CONVENTION).getName();
}
}
Also, a dependency worker showed me well of the methods.
As it seems to works in that link: How do I get a java JNA call to a DLL to get data returned in parameters?, I can see that your definition of ChargerFichier is missing parameters.
Maybe the definition should be something like:
int ChargerFichier(PointerByReference chNom, IntByReference pdwNoSess);
Maybe this link can help you too: http://www.viaboxx.de/code/java-interoperation-with-a-native-dll-using-jna/
This is how you'd use the StdCallFunctionMapper:
Map options = new HashMap();
options.put(Library.OPTION_FUNCTION_MAPPER, new StdCallFunctionMapper());
MyLib lib = (MyLib)Native.loadLibrary("tsr32_mini", MyLib.class, options);
Related
I have implemented a spring boot application to retrieve file data from files and save it in separate collections. When I run the application it gives the following error. I couldn't resolve it. Can anyone help me to do this?
Error
Description:
Parameter 2 of constructor in com.bezkoder.spring.jwt.mongodb.SpringBootSecurityJwtMongodbApplication required a bean of type 'com.bezkoder.spring.jwt.mongodb.models.LogRecordCollection' that could not be found.
Action:
Consider defining a bean of type 'com.bezkoder.spring.jwt.mongodb.models.LogRecordCollection' in your configuration.
Disconnected from the target VM, address: '127.0.0.1:55297', transport: 'socket'
LogRecordController.java
#CrossOrigin(origins = "*", maxAge = 3600)
#RestController
#RequestMapping("/api/auth/log")
public class LogRecordController {
#Autowired
LogRecordRepository logRecordRepository;
#GetMapping("")
public ResponseEntity<?> getAllLogRecordsByLogFileId(#RequestParam("fileId") String fileId) {
try{
LogRecordCollection logRecordCollection = new LogRecordCollection();
logRecordCollection.setCollectionName(fileId);
// List<LogRecord> logRecords = logRecordRepository.findAll(PageRequest.of(1, 10, Sort.by(Sort.Direction.ASC, "no"))).getContent();
List<LogRecord> logRecords = logRecordRepository.findAll();
return ResponseEntity.ok().body(logRecords);
}catch (Exception e){
return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED).body(e.getMessage());
}
}
}
SpringBootSecurityJwtMongodbApplication.java
#SpringBootApplication
#CrossOrigin(origins = "*", maxAge = 3600)
#RestController
#RequestMapping("/api/auth/logFile")
public class SpringBootSecurityJwtMongodbApplication {
public SpringBootSecurityJwtMongodbApplication(LogFileRepository logfileRepo, LogRecordRepository logrecordRepo, LogRecordCollection logrecordColl) {
this.logfileRepo = logfileRepo;
this.logrecordRepo = logrecordRepo;
this.logrecordColl = logrecordColl;
}
public static void main(String[] args) {
SpringApplication.run(SpringBootSecurityJwtMongodbApplication.class, args);
}
#Bean
public ApplicationRunner runner(FTPConfiguration.GateFile gateFile) {
return args -> {
List<File> files = gateFile.mget(".");
for (File file : files) {
JSONArray arr = new JSONArray();
System.out.println("Result:" + file.getAbsolutePath());
run(file, arr);
}
};
}
void run(File file, JSONArray arr) throws IOException {
SimpleDateFormat formatter = new SimpleDateFormat("hh:mm:ss");
Pcap pcap = Pcap.openStream(file);
JSONObject obj = new JSONObject();
String fileName = file.getName();
pcap.loop(
packet -> {
String Time = null;
String Source = null;
String Destination = null;
String dataProtocol = null;
Long Length = null;
if (packet.hasProtocol(Protocol.TCP)) {
TCPPacket packet1 = (TCPPacket) packet.getPacket(Protocol.TCP);
Time = formatter.format(new Date(packet1.getArrivalTime() / 1000));
Source = packet1.getSourceIP();
Destination = packet1.getDestinationIP();
dataProtocol = packet1.getProtocol().toString();
Length = packet1.getTotalLength();
} else if (packet.hasProtocol(Protocol.UDP)) {
UDPPacket packet1 = (UDPPacket) packet.getPacket(Protocol.UDP);
Time = formatter.format(new Date(packet1.getArrivalTime() / 1000));
Source = packet1.getSourceIP();
Destination = packet1.getDestinationIP();
dataProtocol = packet1.getProtocol().toString();
Length = packet1.getTotalLength();
} else {
System.out.println("Not found protocol. | " + packet.getProtocol());
}
obj.put("Time", Time);
obj.put("Source", Source);
obj.put("Destination", Destination);
obj.put("Protocol", dataProtocol);
obj.put("Length", Length);
arr.add(obj);
return packet.getNextPacket() != null;
}
);
System.out.println(arr);
System.out.println(fileName);
Calendar calendar = Calendar.getInstance();
String now = String.valueOf(calendar.getTime());
LogFile data =logfileRepo.save(new LogFile("", fileName, now));
String collectionName = data.getFileName();
System.out.println(collectionName);
//Converting jsonData string into JSON object
//Creating an empty ArrayList of type Object
ArrayList<Object> listdata = new ArrayList<>();
//Checking whether the JSON array has some value or not
if (arr != null) {
//Iterating JSON array
for (int i=0;i<arr.size();i++){
//Adding each element of JSON array into ArrayList
listdata.add(arr.get(i));
}
}
logrecordColl.setCollectionName(collectionName);
listdata.addAll(logrecordRepo.findAll());
}
private final LogFileRepository logfileRepo;
private final LogRecordRepository logrecordRepo;
private final LogRecordCollection logrecordColl;
}
LogRecordRepository.java
import com.bezkoder.spring.jwt.mongodb.models.LogRecord;
import org.springframework.data.mongodb.repository.MongoRepository;
public interface LogRecordRepository extends MongoRepository<LogRecord, String>{
}
LogRecordCollection.java
public class LogRecordCollection {
private static String collectionName = "undefined";
public static String getCollectionName(){
return collectionName;
}
public void setCollectionName(String collectionName){
this.collectionName = collectionName;
}
}
Parameter 2 of constructor in com.bezkoder.spring.jwt.mongodb.SpringBootSecurityJwtMongodbApplication required a bean of type 'com.bezkoder.spring.jwt.mongodb.models.LogRecordCollection' that could not be found.
In an nutshell, the exception like this is self-explanatory. It means that Spring could not find a bean to be injected into your class
In your case the class SpringBootSecurityJwtMongodbApplication has a constructor:
public SpringBootSecurityJwtMongodbApplication(LogFileRepository logfileRepo, LogRecordRepository logrecordRepo, LogRecordCollection logrecordColl) {
this.logfileRepo = logfileRepo;
this.logrecordRepo = logrecordRepo;
this.logrecordColl = logrecordColl;
}
Now, LogRecordCollection has to be a bean (annotated with #Component for example, or defined in via java configuration (#Configuration marked classes and method annotated with #Bean that creates this class). Otherwise spring won't "recognize" this class a bean.
So strictly speaking this is your issue.
Now, having said that - the code you've presented in the question looks extremely messy - you mix #SpringBootApplication which is an entry point to the application, the rest controller and what not. I really recommend you to separate all this to different files to improve the code clarity and avoid unexpected exceptions that can be tricky to fix.
add below annotations in SpringBootSecurityJwtMongodbApplication
#SpringBootApplication
#ComponentScan("com.bezkoder.spring.jwt.mongodb") //to scan packages mentioned
#EnableMongoRepositories("com.bezkoder.spring.jwt.mongodb") //to activate MongoDB repositories
public class SpringBootSecurityJwtMongodbApplication { ... }
I am trying to use kotlin instead of Java, I cannot find a good way to do with try resource:
Java Code like this:
import org.tensorflow.Graph;
import org.tensorflow.Session;
import org.tensorflow.Tensor;
import org.tensorflow.TensorFlow;
public class HelloTensorFlow {
public static void main(String[] args) throws Exception {
try (Graph g = new Graph()) {
final String value = "Hello from " + TensorFlow.version();
// Construct the computation graph with a single operation, a constant
// named "MyConst" with a value "value".
try (Tensor t = Tensor.create(value.getBytes("UTF-8"))) {
// The Java API doesn't yet include convenience functions for adding operations.
g.opBuilder("Const", "MyConst").setAttr("dtype", t.dataType()).setAttr("value", t).build();
}
// Execute the "MyConst" operation in a Session.
try (Session s = new Session(g);
// Generally, there may be multiple output tensors,
// all of them must be closed to prevent resource leaks.
Tensor output = s.runner().fetch("MyConst").run().get(0)) {
System.out.println(new String(output.bytesValue(), "UTF-8"));
}
}
}
}
I do it in kotlin, I have to do this:
fun main(args: Array<String>) {
val g = Graph();
try {
val value = "Hello from ${TensorFlow.version()}"
val t = Tensor.create(value.toByteArray(Charsets.UTF_8))
try {
g.opBuilder("Const", "MyConst").setAttr("dtype", t.dataType()).setAttr("value", t).build()
} finally {
t.close()
}
var sess = Session(g)
try {
val output = sess.runner().fetch("MyConst").run().get(0)
println(String(output.bytesValue(), Charsets.UTF_8))
} finally {
sess?.close()
}
} finally {
g.close()
}
}
I have try to use use like this:
Graph().use {
it -> ....
}
I got error like this:
Error:(16, 20) Kotlin: Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
#InlineOnly public inline fun ???.use(block: (???) -> ???): ??? defined in kotlin.io
I just use wrong dependency:
compile "org.jetbrains.kotlin:kotlin-stdlib"
replace it with:
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
I have to invoke external java methods in xquery using saxon HE. I could able to invoke the methods with the below code. But the problem is i want to bind my input externally.
final Configuration config = new Configuration();
config.registerExtensionFunction(new ShiftLeft());
final StaticQueryContext sqc = new StaticQueryContext(config);
final XQueryExpression exp = sqc.compileQuery(new FileReader(
"input/names.xq"));
final DynamicQueryContext dynamicContext = new DynamicQueryContext(config);
String xml = "<student_list><student><name>George Washington</name><major>Politics</major><phone>312-123-4567</phone><email>gw#example.edu</email></student><student><name>Janet Jones</name><major>Undeclared</major><phone>311-122-2233</phone><email>janetj#example.edu</email></student><student><name>Joe Taylor</name><major>Engineering</major><phone>211-111-2333</phone><email>joe#example.edu</email></student></student_list>";
DocumentBuilderFactory newInstance = DocumentBuilderFactory.newInstance();
newInstance.setNamespaceAware(true);
Document parse = newInstance.newDocumentBuilder().parse(new InputSource(new StringReader(xml)));
DocumentWrapper sequence = new DocumentWrapper(parse, "", config);
StructuredQName qname = new StructuredQName("", "", "student_list");
dynamicContext.setParameter(qname, sequence);
Properties props = new Properties();
final SequenceIterator iter = exp.iterator(dynamicContext);
props.setProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
props.setProperty(OutputKeys.INDENT, "yes");
StringWriter writer = new StringWriter();
QueryResult.serializeSequence(iter, config, writer, props);
System.out.println("Result is " + writer);
names.xq
declare namespace eg="http://example.com/saxon-extension";
declare namespace xs = "http://www.w3.org/2001/XMLSchema";
declare variable $student_list as element(*) external;
<Students>
<value> {
let $n := eg:shift-left(2, 2)
return $n
}</value>
<student_names>
{ $student_list//student_list/student/name }
</student_names>
</Students>
But getting the below error
Error at procedure student_list on line 3 of students.xml:
XPTY0004: Required item type of value of variable $student_list is element(); supplied
value has item type document-node(element(Q{}student_list))
net.sf.saxon.trans.XPathException: Required item type of value of variable $student_list is element(); supplied value has item type document- node(element(Q{}student_list))
at net.sf.saxon.expr.ItemTypeCheckingFunction.testConformance(ItemTypeCheckingFunction.java:69)
at net.sf.saxon.expr.ItemTypeCheckingFunction.mapItem(ItemTypeCheckingFunction.java:50)
at net.sf.saxon.expr.ItemMappingIterator.next(ItemMappingIterator.java:95)
at net.sf.saxon.expr.CardinalityCheckingIterator.<init>(CardinalityCheckingIterator.java:52)
at net.sf.saxon.type.TypeHierarchy.applyFunctionConversionRules(TypeHierarchy.java:230)
at net.sf.saxon.expr.instruct.GlobalParameterSet.convertParameterValue(GlobalParameterSet.java:105)
at net.sf.saxon.expr.instruct.Bindery.useGlobalParameter(Bindery.java:136)
at net.sf.saxon.expr.instruct.GlobalParam.evaluateVariable(GlobalParam.java:62)
at net.sf.saxon.expr.GlobalVariableReference.evaluateVariable(GlobalVariableReference.java:105)
at net.sf.saxon.expr.VariableReference.evaluateItem(VariableReference.java:460)
at net.sf.saxon.expr.Atomizer.evaluateItem(Atomizer.java:313)
at net.sf.saxon.expr.Atomizer.evaluateItem(Atomizer.java:35)
at net.sf.saxon.expr.AtomicSequenceConverter.evaluateItem(AtomicSequenceConverter.java:275)
at net.sf.saxon.expr.AtomicSequenceConverter.evaluateItem(AtomicSequenceConverter.java:30)
at net.sf.saxon.functions.Doc.doc(Doc.java:235)
at net.sf.saxon.functions.Doc.evaluateItem(Doc.java:190)
at net.sf.saxon.functions.Doc.evaluateItem(Doc.java:28)
at net.sf.saxon.expr.SimpleStepExpression.iterate(SimpleStepExpression.java:85)
at net.sf.saxon.expr.SlashExpression.iterate(SlashExpression.java:842)
at net.sf.saxon.expr.sort.DocumentSorter.iterate(DocumentSorter.java:168)
at net.sf.saxon.expr.SlashExpression.iterate(SlashExpression.java:842)
at net.sf.saxon.expr.sort.DocumentSorter.iterate(DocumentSorter.java:168)
at net.sf.saxon.expr.Expression.process(Expression.java:552)
at net.sf.saxon.expr.instruct.ElementCreator.processLeavingTail(ElementCreator.java:450)
at net.sf.saxon.expr.instruct.ElementCreator.processLeavingTail(ElementCreator.java:389)
at net.sf.saxon.expr.instruct.Block.processLeavingTail(Block.java:669)
at net.sf.saxon.expr.instruct.Instruction.process(Instruction.java:144)
at net.sf.saxon.expr.instruct.ElementCreator.constructElement(ElementCreator.java:539)
at net.sf.saxon.expr.instruct.ElementCreator.evaluateItem(ElementCreator.java:476)
at net.sf.saxon.expr.instruct.Instruction.iterate(Instruction.java:363)
at net.sf.saxon.query.XQueryExpression.iterator(XQueryExpression.java:332)
at com.example.saxon.ExternalMethodCaller.main(ExternalMethodCaller.java:77)
Thanks in advance..
Unless you have a very good reason not to, my advice is to use Snappi (the Saxon 9 API, or s9api):
Processor saxon = new Processor(false);
saxon.registerExtensionFunction(new MyExtension());
XQueryCompiler compiler = saxon.newXQueryCompiler();
XQueryExecutable exec = compiler.compile(new File("input/names.xq"));
XQueryEvaluator query = exec.load();
DocumentBuilder builder = saxon.newDocumentBuilder();
String students = "<xml>...</xml>";
Source src = new StreamSource(new StringReader(students));
XdmNode doc = builder.build(src);
query.setExternalVariable(new QName("student_list"), doc);
XdmValue result = query.evaluate();
With MyExtension looking something like the following:
public class MyExtension
implements ExtensionFunction
{
#Override
public QName getName()
{
return new QName("http://example.org/my-project", "my-fun");
}
#Override
public SequenceType getResultType()
{
return SequenceType.makeSequenceType(
ItemType.INTEGER, OccurrenceIndicator.ONE);
}
#Override
public SequenceType[] getArgumentTypes()
{
return new SequenceType[] {
SequenceType.makeSequenceType(
ItemType.INTEGER, OccurrenceIndicator.ONE),
SequenceType.makeSequenceType(
ItemType.INTEGER, OccurrenceIndicator.ONE)
};
}
#Override
public XdmValue call(XdmValue[] args) throws SaxonApiException
{
long first = ((XdmAtomicValue)args[0].itemAt(0)).getLongValue();
long second = ((XdmAtomicValue)args[0].itemAt(0)).getLongValue();
long result = ...;
return new XdmAtomicValue(result);
}
}
See the documentation at http://www.saxonica.com/documentation9.5/extensibility/integratedfunctions/ext-simple-J.html for details.
EXPath also has a project called tools-saxon, containing several tools for using Saxon in Java. Including extension functions. It introduces the concept of a function library, which is convenient if you have several extension functions. It also introduces a function definition builder, allowing one to build a function definition with as less boiler plate code as possible (and providing convenient shortcuts for type sequences). In the above code, replace the function registering (the first 2 lines) by:
Processor saxon = new Processor(false);
Library lib = new MyLibrary();
lib.register(saxon.getUnderlyingConfiguration());
and replace the extension class with the 2 following classes (a library and a function, resp.):
public class MyLibrary
extends Library
{
public MyLibrary()
{
super("http://example.org/my-project", "my");
}
#Override
protected Function[] functions()
{
return new Function[] {
new MyFunction(this)
};
}
}
public class MyFunction
extends Function
{
public MyFunction(Library lib)
{
super(lib);
}
#Override
protected Definition makeDefinition()
{
return library()
.function(this, "my-fun")
.returns(Types.SINGLE_INTEGER)
.param(Types.SINGLE_INTEGER, "first")
.param(Types.SINGLE_INTEGER, "second")
.make();
}
#Override
public Sequence call(XPathContext ctxt, Sequence[] args)
throws XPathException
{
Parameters params = checkParams(args);
long first = params.asLong(0, true);
long second = params.asLong(1, true);
long result = 0;
return Return.value(result);
}
}
See all informatio on the project home on Github, at https://github.com/expath/tools-saxon.
Note: not tested.
Here are the two java classes:
package je3.io;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* Created by IDEA on 31/01/15.
*/
public class DirWalker {
private List<File> recursiveList = new ArrayList<File>();
public void walkDir(String pathname) {
File d = new File(pathname);
recursiveList.add(d);
if(d.isDirectory()) {
for(String f : d.list()) {
walkDir(f);
}
}
}
public void reset() {
recursiveList.clear();
}
public List<File> getRecursiveList() {
return recursiveList;
}
public static void main(String[] args) {
DirWalker dirWalker = new DirWalker();
dirWalker.walkDir("/tmp");
dirWalker.getRecursiveList().forEach(System.out::println);
}
}
package je3.io;
import java.io.File;
/**
* Created by IDEA on 31/01/15.
*/
public class DirSummariser {
private DirWalker dirWalker = new DirWalker();
private long dirSize = 0;
public DirSummariser(String pathname) {
dirWalker.reset();
dirWalker.walkDir(pathname);
}
public DirSummariser(File file) {
this(file.getAbsolutePath());
}
public long calculateDirSize() {
for(File f : dirWalker.getRecursiveList()) {
dirSize += f.length();
}
return dirSize;
}
public static void main(String[] args) {
DirSummariser dirSummariser = new DirSummariser("/Users/hualin/Downloads/pdf");
System.out.println(dirSummariser.calculateDirSize());
}
}
In the main method of the second class, I was trying to calculate the total size of the pdf folder, which should be around 30MB. The java program compiles without error, but says the size of the folder is only 1600 bytes.
The problem is in DirWalker:
public void walkDir(String pathname) {
File d = new File(pathname);
recursiveList.add(d);
if(d.isDirectory()) {
for(String f : d.list()) { // <-- here
walkDir(f); // <--
}
}
}
The strings returned by d.list() are just the file names, without a path attached to them. If you find, for example, a file some_directory/foo.txt, the string you'll pull out of the list is foo.txt, and since foo.txt is not in the current working directory, the File object you construct from it will be invalid (or describe a different file).
You'll have to make the path you're trying to inspect part of the recursion to make this work properly, for example like this:
walkDir(pathname + File.separator + f);
Or, as #Adam mentions in the comments, by passing the File object that describes the parent directory into the recursion and using the File(parent, child) constructor, as in
// new parameter here: parent directory
public void walkDir(String pathname, File parent) {
System.out.println(pathname);
File d = new File(parent, pathname); // <-- File constructor with parent
recursiveList.add(d);
if(d.isDirectory()) {
for(String f : d.list()) {
walkDir(f, d); // passing parent here
}
}
}
// entry point, to keep old interface.
public void walkDir(String pathname) {
walkDir(pathname, null);
}
Note: This answer, I think this should be mentioned, is rather tailored to OP's use case of an exercise, so I mainly tried to explain why his code didn't work and suggested ways to make it work. If you're a stray visitor in the future and looking for ways to walk through a directory with Java, look at #fge's answer for a better way.
Use the java.nio.file API, it's much better at doing things like this.
Here is an example, also using throwing-lambdas, calculating the total size of all files in a directory, recursively:
final Path theDirectory = Paths.get("path/to/your/directory");
final long totalSize = Files.walk(theDirectory)
.filter(Files::isRegularFile)
.mapToLong(Functions.rethrow(Files::size))
.sum();
If you don't have Java 8, use Files.walkFileTree().
Lets say I have a java package commands which contains classes that all inherit from ICommand can I get all of those classes somehow? I'm locking for something among the lines of:
Package p = Package.getPackage("commands");
Class<ICommand>[] c = p.getAllPackagedClasses(); //not real
Is something like that possible?
Here's a basic example, assuming that classes are not JAR-packaged:
// Prepare.
String packageName = "com.example.commands";
List<Class<ICommand>> commands = new ArrayList<Class<ICommand>>();
URL root = Thread.currentThread().getContextClassLoader().getResource(packageName.replace(".", "/"));
// Filter .class files.
File[] files = new File(root.getFile()).listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.endsWith(".class");
}
});
// Find classes implementing ICommand.
for (File file : files) {
String className = file.getName().replaceAll(".class$", "");
Class<?> cls = Class.forName(packageName + "." + className);
if (ICommand.class.isAssignableFrom(cls)) {
commands.add((Class<ICommand>) cls);
}
}
Below is an implementation using the JSR-199 API, i.e. classes from javax.tools.*:
List<Class> commands = new ArrayList<>();
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(
null, null, null);
StandardLocation location = StandardLocation.CLASS_PATH;
String packageName = "commands";
Set<JavaFileObject.Kind> kinds = new HashSet<>();
kinds.add(JavaFileObject.Kind.CLASS);
boolean recurse = false;
Iterable<JavaFileObject> list = fileManager.list(location, packageName,
kinds, recurse);
for (JavaFileObject classFile : list) {
String name = classFile.getName().replaceAll(".*/|[.]class.*","");
commands.add(Class.forName(packageName + "." + name));
}
Works for all packages and classes on the class path, packaged in jar files or without. For classes not explicitly added to the class path, i.e. those loaded by the bootstrap class loader, try setting location to PLATFORM_CLASS_PATH instead.
Here is an utility method, using Spring.
Details about the pattern can be found here
public static List<Class> listMatchingClasses(String matchPattern) throws IOException {
List<Class> classes = new LinkedList<Class>();
PathMatchingResourcePatternResolver scanner = new PathMatchingResourcePatternResolver();
Resource[] resources = scanner.getResources(matchPattern);
for (Resource resource : resources) {
Class<?> clazz = getClassFromResource(resource);
classes.add(clazz);
}
return classes;
}
public static Class getClassFromResource(Resource resource) {
try {
String resourceUri = resource.getURI().toString();
resourceUri = resourceUri.replace(esourceUri.indexOf(".class"), "").replace("/", ".");
// try printing the resourceUri before calling forName, to see if it is OK.
return Class.forName(resourceUri);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
If you do not want to use external depencies and you want to work on your IDE / on a JAR file, you can try this:
public static List<Class<?>> getClassesForPackage(final String pkgName) throws IOException, URISyntaxException {
final String pkgPath = pkgName.replace('.', '/');
final URI pkg = Objects.requireNonNull(ClassLoader.getSystemClassLoader().getResource(pkgPath)).toURI();
final ArrayList<Class<?>> allClasses = new ArrayList<Class<?>>();
Path root;
if (pkg.toString().startsWith("jar:")) {
try {
root = FileSystems.getFileSystem(pkg).getPath(pkgPath);
} catch (final FileSystemNotFoundException e) {
root = FileSystems.newFileSystem(pkg, Collections.emptyMap()).getPath(pkgPath);
}
} else {
root = Paths.get(pkg);
}
final String extension = ".class";
try (final Stream<Path> allPaths = Files.walk(root)) {
allPaths.filter(Files::isRegularFile).forEach(file -> {
try {
final String path = file.toString().replace('/', '.');
final String name = path.substring(path.indexOf(pkgName), path.length() - extension.length());
allClasses.add(Class.forName(name));
} catch (final ClassNotFoundException | StringIndexOutOfBoundsException ignored) {
}
});
}
return allClasses;
}
From: Can you find all classes in a package using reflection?
Start with public Classloader.getResources(String name). Ask the classloader for a class corresponding to each name in the package you are interested. Repeat for all classloaders of relevance.
Yes but its not the easiest thing to do. There are lots of issues with this. Not all of the classes are easy to find. Some classes could be in a: Jar, as a class file, over the network etc.
Take a look at this thread.
To make sure they were the ICommand type then you would have to use reflection to check for the inheriting class.
This would be a very useful tool we need, and JDK should provide some support.
But it's probably better done during build. You know where all your class files are and you can inspect them statically and build a graph. At runtime you can query this graph to get all subtypes. This requires more work, but I believe it really belongs to the build process.
Using Johannes Link's ClasspathSuite, I was able to do it like this:
import org.junit.extensions.cpsuite.ClassTester;
import org.junit.extensions.cpsuite.ClasspathClassesFinder;
public static List<Class<?>> getClasses(final Package pkg, final boolean includeChildPackages) {
return new ClasspathClassesFinder(new ClassTester() {
#Override public boolean searchInJars() { return true; }
#Override public boolean acceptInnerClass() { return false; }
#Override public boolean acceptClassName(String name) {
return name.startsWith(pkg.getName()) && (includeChildPackages || name.indexOf(".", pkg.getName().length()) != -1);
}
#Override public boolean acceptClass(Class<?> c) { return true; }
}, System.getProperty("java.class.path")).find();
}
The ClasspathClassesFinder looks for class files and jars in the system classpath.
In your specific case, you could modify acceptClass like this:
#Override public boolean acceptClass(Class<?> c) {
return ICommand.class.isAssignableFrom(c);
}
One thing to note: be careful what you return in acceptClassName, as the next thing ClasspathClassesFinder does is to load the class and call acceptClass. If acceptClassName always return true, you'll end up loading every class in the classpath and that may cause an OutOfMemoryError.
You could use OpenPojo and do this:
final List<PojoClass> pojoClasses = PojoClassFactory.getPojoClassesRecursively("my.package.path", null);
Then you can go over the list and perform any functionality you desire.