Hi all, In order to create a module for my agent at runtime I had to provide my own implementations of classes ModuleFinder and ModuleReader. These implementations delegate to the agent in order to retrieve bytecode for a given class contained in the module so they do not themselves rely on a file located on disk or on the network to provide this bytecode.
The implementations I came up with both appear to work but I am not really sure why I needed to implement them the way I have. Perhaps someone might be able to answer two questions I have, one for each implementation: 1) My ModuleFinder class, JigsawModuleFinder, has to implement method find(String), returning a ModuleReference for a given module name and findall() return a Set<ModuleReferences>. I implemented the API as follows public class JigsawModuleFinder implements ModuleFinder . . . public Optional<ModuleReference> find(String name) { if (moduleName.equals(name)) { return Optional.of(getModuleReference()); }; return null; } public Set<ModuleReference> findAll() { return Set.of(getModuleReference()); } . . . n.b. in the first implementation moduleName is a String instance field naming the single module that my Finder is meant to find. The (sole) module reference returned by these two methods is created by method getModuleReference as follows private ModuleReference getModuleReference() { URI uri = null; try { uri = new URI("byteman", moduleName, null); } catch (URISyntaxException e) { } ModuleDescriptor desc = new ModuleDescriptor.Builder(moduleName). requires("java.instrument"). exports(packageName). build(); final ModuleReader reader = new JigsawModuleReader(classMapper); ModuleReference reference = new ModuleReference(desc, uri, new Supplier<ModuleReader>() { @Override public ModuleReader get() { return reader; } }); return reference; } n.b. classMapper is another instance field which identifies a Map<String, byte[]> supplied by my agent. It's get method maps class names to the corresponding class format byte[]. The part I am dubious about here is the URI, in particular the need to provide a scheme (supplied as the String "byteman"). I passed that because I get an error if I simply pass null for the scheme (it complains that this is not an absolute URI). I can see that the module should have a name but why does it need to be absolute? Indeed, why is it needed at all? The various javadocs eventually lead to a suggestion that the URI may be used by a security manager. If this is really what it is for then do I need to worry about having invented scheme 'byteman' out of thin air? WIl the security code ever try to convert it to a URL? 2) A related conundrum arises with my class Modulereader class, JigsawModuleReader. It implements the public API as follows public class JigsawModuleReader implements ModuleReader { . . . public Optional<URI> find(String name) throws IOException { return Optional.empty(); } public Optional<ByteBuffer> read(String name) throws IOException { byte[] classBytes = classMapper.get(name); if (classBytes != null) { ByteBuffer byteBuffer = ByteBuffer.wrap(classBytes) ; return Optional.of(byteBuffer); } return Optional.empty(); } public void close() throws IOException { // nothing to do } } I am required to implement find as it has no default. I also need to implement read so I can redirect to the agent to provide the class format byte[]. However, it appears that find is only needed so it can be called from the default method open and that open is only there to be called from the default method read. Is there any possibility that something else might call find? Thanks for any help that anyone on the list can provide. regards, Andrew Dinn ----------- Senior Principal Software Engineer Red Hat UK Ltd Registered in England and Wales under Company Registration No. 03798903 Directors: Michael Cunningham, Michael ("Mike") O'Neill, Eric Shander