I'm trying to run the JAAS code sample.
lc = new LoginContext("JaasSample", new TextCallbackHandler());
To register the configuration file I try the command:
java -Djava.security.auth.login.config=jaas.config JaasAcn
And gets the error:
Error: Could not find or load main class .security.auth.login.config=jaas.config
Caused by: java.lang.ClassNotFoundException: /security/auth/login/config=jaas/config
Firstly write javax instead of java, so:
java -Djavax.security.auth.login.config=jaas.config JaasAcn
And second, consider to config it programmicly:
Inherit the javax.security.auth.login.Configuration class.
Override the function AppConfigurationEntry[] getAppConfigurationEntry(String name). In this func you can return an AppConfigurationEntry object that represent a row in config file.
new AppConfigurationEntry(NTLoginModule.class.getName(),
AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, new HashMap<>())
With name parameter you can responde for the name parameter in LoginContext constructor.
Create object from your Configuration class and put him in Configuration:
MyConfiguration config = new MyConfiguration();
Configuration.setConfiguration(config);
The shortened code can look like this:
Configuration config = new Configuration() {
#Override
public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
return new AppConfigurationEntry[]{
new AppConfigurationEntry(NTLoginModule.class.getName(),
AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
new HashMap<>())
};
}
};
Configuration.setConfiguration(config);
Clearly there is a typo in the command line: a space after -Djava, so the .security.auth.login.config=jaas.config part is taken as the class name (and hence also mangled accordingly).
We have an ability to compile java code dynamically on the fly.
I know at least Java-Runtime-Compiler and InMemoryJavaCompiler
But seems they cannot compile class which depends on some class from certain classloader.
Is it possible to dynamically compile java code which depends on classes available only in specific classloader? Let's say:
ClassLoader classloader = ... // only this CL can load class 'com.External'
String source = "public class MyClass extends com.External {}";
Class<?> compiled = DesiredDynamicCompiler.compile("MyClass", source, classloader);
// last argument is like an information to compiler where to search all dependencies
To provide more insight: I would like to do in java what exactly GroovyClassLoader can do in groovy:
GroovyClassLoader groovyClassLoader = new GroovyClassLoader(classLoader);
Class<?> parsedClass = groovyClassLoader.parseClass("some source");
That code can parse class which depends on classes available only in specified classloader.
There is no way to use a ClassLoader as reference, unless it is capable of providing the class bytes of its defined classes. I.e., if you have a Class instance representing a top-level class, you can use classInstance.getResourceAsStream(classInstance.getSimpleName()+".class") to try to get hands on the class bytes. If you have access to the bytes that make up the dynamic class, you can make them available to the java compiler via a JavaFileManager implementation.
The compiler API is part of the standard API and doesn’t require 3rd party libraries. The following code demonstrates this by compiling a test class first, then setting the necessary environment to compile a second class depending on the class just created in the previous step:
// customize these, if you want, null triggers default behavior
DiagnosticListener<JavaFileObject> diagnosticListener = null;
Locale locale = null;
// the first class, to be present at runtime only
String class1 = "package test;\npublic class Class1 {}";
JavaCompiler c = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fm
= c.getStandardFileManager(diagnosticListener, locale, Charset.defaultCharset());
// define where to store compiled class files - use a temporary directory
fm.setLocation(StandardLocation.CLASS_OUTPUT, Collections.singleton(
Files.createTempDirectory("compile-test").toFile()));
JavaCompiler.CompilationTask task = c.getTask(null, fm,
diagnosticListener, Collections.emptySet(), Collections.emptySet(),
Collections.singleton(new SimpleJavaFileObject(
URI.create("string:///Class1.java"), Kind.SOURCE) {
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return class1;
}
}));
if(task.call()) {
FileObject fo = fm.getJavaFileForInput(
StandardLocation.CLASS_OUTPUT, "test.Class1", Kind.CLASS);
// these are the class bytes of the first class
byte[] class1bytes = Files.readAllBytes(Paths.get(fo.toUri()));
// the actual task: define a class dependent on the first class
String class2 = "package test;\npublic class Class2 { Class1 variable; }";
// create a file object representing the dynamic class
JavaFileObject jo = new SimpleJavaFileObject(
URI.create("runtime:///test/Class1.class"), Kind.CLASS) {
#Override public InputStream openInputStream() throws IOException {
return new ByteArrayInputStream(class1bytes);
}
};
// and a custom file manager knowing how to locate that class
JavaFileManager myFM = new ForwardingJavaFileManager(fm) {
#Override
public JavaFileObject getJavaFileForInput(
JavaFileManager.Location location, String className, Kind kind)
throws IOException {
if(location==StandardLocation.CLASS_PATH&&className.equals("test.Class1")) {
return jo;
}
return super.getJavaFileForInput(location, className, kind);
}
#Override
public boolean hasLocation(JavaFileManager.Location location) {
return location==StandardLocation.CLASS_PATH || super.hasLocation(location);
}
#Override
public Iterable list(JavaFileManager.Location location,
String packageName, Set kinds, boolean recurse) throws IOException {
if(location==StandardLocation.CLASS_PATH
&& (packageName.equals("test") || recurse&&packageName.isEmpty())) {
return Collections.singleton(jo);
}
return super.list(location, packageName, kinds, recurse);
}
#Override
public String inferBinaryName(
JavaFileManager.Location location, JavaFileObject file) {
if(file==jo) return "test.Class1";
return super.inferBinaryName(location, file);
}
};
// compile the second class using the custom file manager to locate dependencies
task = c.getTask(null, myFM,
diagnosticListener, Collections.emptySet(), Collections.emptySet(),
Collections.singleton(new SimpleJavaFileObject(
URI.create("string:///Class2.java"), Kind.SOURCE) {
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return class2;
}
}));
if(task.call()) {
fo = fm.getJavaFileForInput(
StandardLocation.CLASS_OUTPUT, "test.Class2", Kind.CLASS);
// there we have the compiled second class
byte[] class2bytes = Files.readAllBytes(Paths.get(fo.toUri()));
}
}
Of course, this is only for demonstrating the principle. You surely want to create factory methods for the file objects and use Maps for remembering them, etc.
It’s also possible to replace the temporary directory with a custom in-memory storage. But the key point remains, that the compiler needs to be able to access the class bytes. It won’t use loaded runtime classes.
You should have all the dependencies on your class path. The tools you've referenced use Java Compiler API under the cover anyway.
It doesn't interact with classes in current JVM's memory, it only searches for dependencies in the classpath.
You can follow through CompilerUtils -> com.sun.tools.javac.api.JavacTool -> further to get some feeling of what happens there.
One thing you can try to do is to have your dynamically compiled dependencies dumped to proper place in classpath as .class files so that your compilation process will pick them up.
How does one go about and try to find all subclasses of a given class (or all implementors of a given interface) in Java?
As of now, I have a method to do this, but I find it quite inefficient (to say the least).
The method is:
Get a list of all class names that exist on the class path
Load each class and test to see if it is a subclass or implementor of the desired class or interface
In Eclipse, there is a nice feature called the Type Hierarchy that manages to show this quite efficiently.
How does one go about and do it programmatically?
Scanning for classes is not easy with pure Java.
The spring framework offers a class called ClassPathScanningCandidateComponentProvider that can do what you need. The following example would find all subclasses of MyClass in the package org.example.package
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
provider.addIncludeFilter(new AssignableTypeFilter(MyClass.class));
// scan in org.example.package
Set<BeanDefinition> components = provider.findCandidateComponents("org/example/package");
for (BeanDefinition component : components)
{
Class cls = Class.forName(component.getBeanClassName());
// use class cls found
}
This method has the additional benefit of using a bytecode analyzer to find the candidates which means it will not load all classes it scans.
There is no other way to do it other than what you described. Think about it - how can anyone know what classes extend ClassX without scanning each class on the classpath?
Eclipse can only tell you about the super and subclasses in what seems to be an "efficient" amount of time because it already has all of the type data loaded at the point where you press the "Display in Type Hierarchy" button (since it is constantly compiling your classes, knows about everything on the classpath, etc).
This is not possible to do using only the built-in Java Reflections API.
A project exists that does the necessary scanning and indexing of your classpath so you can get access this information...
Reflections
A Java runtime metadata analysis, in the spirit of Scannotations
Reflections scans your classpath, indexes the metadata, allows you to query it on runtime and may save and collect that information for many modules within your project.
Using Reflections you can query your metadata for:
get all subtypes of some type
get all types annotated with some annotation
get all types annotated with some annotation, including annotation parameters matching
get all methods annotated with some
(disclaimer: I have not used it, but the project's description seems to be an exact fit for your needs.)
Try ClassGraph. (Disclaimer, I am the author). ClassGraph supports scanning for subclasses of a given class, either at runtime or at build time, but also much more. ClassGraph can build an abstract representation of the entire class graph (all classes, annotations, methods, method parameters, and fields) in memory, for all classes on the classpath, or for classes in selected packages, and you can query this class graph however you want. ClassGraph supports more classpath specification mechanisms and classloaders than any other scanner, and also works seamlessly with the new JPMS module system, so if you base your code on ClassGraph, your code will be maximally portable. See the API here.
Don't forget that the generated Javadoc for a class will include a list of known subclasses (and for interfaces, known implementing classes).
I know I'm a few years late to this party, but I came across this question trying to solve the same problem. You can use Eclipse's internal searching programatically, if you're writing an Eclipse Plugin (and thus take advantage of their caching, etc), to find classes which implement an interface. Here's my (very rough) first cut:
protected void listImplementingClasses( String iface ) throws CoreException
{
final IJavaProject project = <get your project here>;
try
{
final IType ifaceType = project.findType( iface );
final SearchPattern ifacePattern = SearchPattern.createPattern( ifaceType, IJavaSearchConstants.IMPLEMENTORS );
final IJavaSearchScope scope = SearchEngine.createWorkspaceScope();
final SearchEngine searchEngine = new SearchEngine();
final LinkedList<SearchMatch> results = new LinkedList<SearchMatch>();
searchEngine.search( ifacePattern,
new SearchParticipant[]{ SearchEngine.getDefaultSearchParticipant() }, scope, new SearchRequestor() {
#Override
public void acceptSearchMatch( SearchMatch match ) throws CoreException
{
results.add( match );
}
}, new IProgressMonitor() {
#Override
public void beginTask( String name, int totalWork )
{
}
#Override
public void done()
{
System.out.println( results );
}
#Override
public void internalWorked( double work )
{
}
#Override
public boolean isCanceled()
{
return false;
}
#Override
public void setCanceled( boolean value )
{
}
#Override
public void setTaskName( String name )
{
}
#Override
public void subTask( String name )
{
}
#Override
public void worked( int work )
{
}
});
} catch( JavaModelException e )
{
e.printStackTrace();
}
}
The first problem I see so far is that I'm only catching classes which directly implement the interface, not all their subclasses - but a little recursion never hurt anyone.
I did this several years ago. The most reliable way to do this (i.e. with official Java APIs and no external dependencies) is to write a custom doclet to produce a list that can be read at runtime.
You can run it from the command line like this:
javadoc -d build -doclet com.example.ObjectListDoclet -sourcepath java/src -subpackages com.example
or run it from ant like this:
<javadoc sourcepath="${src}" packagenames="*" >
<doclet name="com.example.ObjectListDoclet" path="${build}"/>
</javadoc>
Here's the basic code:
public final class ObjectListDoclet {
public static final String TOP_CLASS_NAME = "com.example.MyClass";
/** Doclet entry point. */
public static boolean start(RootDoc root) throws Exception {
try {
ClassDoc topClassDoc = root.classNamed(TOP_CLASS_NAME);
for (ClassDoc classDoc : root.classes()) {
if (classDoc.subclassOf(topClassDoc)) {
System.out.println(classDoc);
}
}
return true;
}
catch (Exception ex) {
ex.printStackTrace();
return false;
}
}
}
For simplicity, I've removed command line argument parsing and I'm writing to System.out rather than a file.
Keeping in mind the limitations mentioned in the other answers, you can also use openpojo's PojoClassFactory (available on Maven) in the following manner:
for(PojoClass pojoClass : PojoClassFactory.enumerateClassesByExtendingType(packageRoot, Superclass.class, null)) {
System.out.println(pojoClass.getClazz());
}
Where packageRoot is the root String of the packages you wish to search in (e.g. "com.mycompany" or even just "com"), and Superclass is your supertype (this works on interfaces as well).
Depending on your particular requirements, in some cases Java's service loader mechanism might achieve what you're after.
In short, it allows developers to explicitly declare that a class subclasses some other class (or implements some interface) by listing it in a file in the JAR/WAR file's META-INF/services directory. It can then be discovered using the java.util.ServiceLoader class which, when given a Class object, will generate instances of all the declared subclasses of that class (or, if the Class represents an interface, all the classes implementing that interface).
The main advantage of this approach is that there is no need to manually scan the entire classpath for subclasses - all the discovery logic is contained within the ServiceLoader class, and it only loads the classes explicitly declared in the META-INF/services directory (not every class on the classpath).
There are, however, some disadvantages:
It won't find all subclasses, only those that are explicitly declared. As such, if you need to truly find all subclasses, this approach may be insufficient.
It requires the developer to explicitly declare the class under the META-INF/services directory. This is an additional burden on the developer, and can be error-prone.
The ServiceLoader.iterator() generates subclass instances, not their Class objects. This causes two issues:
You don't get any say on how the subclasses are constructed - the no-arg constructor is used to create the instances.
As such, the subclasses must have a default constructor, or must explicity declare a no-arg constructor.
Apparently Java 9 will be addressing some of these shortcomings (in particular, the ones regarding instantiation of subclasses).
An Example
Suppose you're interested in finding classes that implement an interface com.example.Example:
package com.example;
public interface Example {
public String getStr();
}
The class com.example.ExampleImpl implements that interface:
package com.example;
public class ExampleImpl implements Example {
public String getStr() {
return "ExampleImpl's string.";
}
}
You would declare the class ExampleImpl is an implementation of Example by creating a file META-INF/services/com.example.Example containing the text com.example.ExampleImpl.
Then, you could obtain an instance of each implementation of Example (including an instance of ExampleImpl) as follows:
ServiceLoader<Example> loader = ServiceLoader.load(Example.class)
for (Example example : loader) {
System.out.println(example.getStr());
}
// Prints "ExampleImpl's string.", plus whatever is returned
// by other declared implementations of com.example.Example.
It should be noted as well that this will of course only find all those subclasses that exist on your current classpath. Presumably this is OK for what you are currently looking at, and chances are you did consider this, but if you have at any point released a non-final class into the wild (for varying levels of "wild") then it is entirely feasible that someone else has written their own subclass that you will not know about.
Thus if you happened to be wanting to see all subclasses because you want to make a change and are going to see how it affects subclasses' behaviour - then bear in mind the subclasses that you can't see. Ideally all of your non-private methods, and the class itself should be well-documented; make changes according to this documentation without changing the semantics of methods/non-private fields and your changes should be backwards-compatible, for any subclass that followed your definition of the superclass at least.
The reason you see a difference between your implementation and Eclipse is because you scan each time, while Eclipse (and other tools) scan only once (during project load most of the times) and create an index. Next time you ask for the data it doesn't scan again, but look at the index.
I'm using a reflection lib, which scans your classpath for all subclasses: https://github.com/ronmamo/reflections
This is how it would be done:
Reflections reflections = new Reflections("my.project");
Set<Class<? extends SomeType>> subTypes = reflections.getSubTypesOf(SomeType.class);
You can use org.reflections library and then, create an object of Reflections class. Using this object, you can get list of all subclasses of given class.
https://www.javadoc.io/doc/org.reflections/reflections/0.9.10/org/reflections/Reflections.html
Reflections reflections = new Reflections("my.project.prefix");
System.out.println(reflections.getSubTypesOf(A.class)));
Add them to a static map inside (this.getClass().getName()) the parent classes constructor (or create a default one) but this will get updated in runtime. If lazy initialization is an option you can try this approach.
I just write a simple demo to use the org.reflections.Reflections to get subclasses of abstract class:
https://github.com/xmeng1/ReflectionsDemo
I needed to do this as a test case, to see if new classes had been added to the code. This is what I did
final static File rootFolder = new File(SuperClass.class.getProtectionDomain().getCodeSource().getLocation().getPath());
private static ArrayList<String> files = new ArrayList<String>();
listFilesForFolder(rootFolder);
#Test(timeout = 1000)
public void testNumberOfSubclasses(){
ArrayList<String> listSubclasses = new ArrayList<>(files);
listSubclasses.removeIf(s -> !s.contains("Superclass.class"));
for(String subclass : listSubclasses){
System.out.println(subclass);
}
assertTrue("You did not create a new subclass!", listSubclasses.size() >1);
}
public static void listFilesForFolder(final File folder) {
for (final File fileEntry : folder.listFiles()) {
if (fileEntry.isDirectory()) {
listFilesForFolder(fileEntry);
} else {
files.add(fileEntry.getName().toString());
}
}
}
If you intend to load all subclassess of given class which are in the same package, you can do so:
public static List<Class> loadAllSubClasses(Class pClazz) throws IOException, ClassNotFoundException {
ClassLoader classLoader = pClazz.getClassLoader();
assert classLoader != null;
String packageName = pClazz.getPackage().getName();
String dirPath = packageName.replace(".", "/");
Enumeration<URL> srcList = classLoader.getResources(dirPath);
List<Class> subClassList = new ArrayList<>();
while (srcList.hasMoreElements()) {
File dirFile = new File(srcList.nextElement().getFile());
File[] files = dirFile.listFiles();
if (files != null) {
for (File file : files) {
String subClassName = packageName + '.' + file.getName().substring(0, file.getName().length() - 6);
if (! subClassName.equals(pClazz.getName())) {
subClassList.add(Class.forName(subClassName));
}
}
}
}
return subClassList;
}
find all classes in classpath
public static List<String> getClasses() {
URLClassLoader urlClassLoader = (URLClassLoader) Thread.currentThread().getContextClassLoader();
List<String> classes = new ArrayList<>();
for (URL url : urlClassLoader.getURLs()) {
try {
if (url.toURI().getScheme().equals("file")) {
File file = new File(url.toURI());
if (file.exists()) {
try {
if (file.isDirectory()) {
for (File listFile : FileUtils.listFiles(file, new String[]{"class"}, true)) {
String classFile = listFile.getAbsolutePath().replace(file.getAbsolutePath(), "").replace(".class", "");
if (classFile.startsWith(File.separator)) {
classFile = classFile.substring(1);
}
classes.add(classFile.replace(File.separator, "."));
}
} else {
JarFile jarFile = new JarFile(file);
if (url.getFile().endsWith(".jar")) {
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry jarEntry = entries.nextElement();
if (jarEntry.getName().endsWith(".class")) {
classes.add(jarEntry.getName().replace(".class", "").replace("/", "."));
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
return classes;
}
enter link description hereService Manager in java will get all implementing classes for an interface in J
I've looked at the following question and it is not the same as mine:
jMockit: How to expect constructor calls to Mocked objects?
This question is similar but the answer is not helpful to me:
How to mock the default constructor of the Date class with JMockit?
What I am trying to do is mock a constructor call to java.util.zip.ZipFile, specifically the one that has a java.io.File argument. I would like for the constructor to return an instance of a different ZipFile, one I will instantiate with the constructor that only takes a String argument.
This constructor call takes place inside a method under test, so I can't inject the ZipFile I want as a parameter.
For example, the code looks something like this:
public void whatever() {
//some code
//some more code
foo();
//yet more unrelated code
}
private Blah foo() {
ZipFile zf;
//a bunch of code we don't care about
zf = new ZipFile(someFile);// I want to give it a known zipfile! mock this!
// some more code we don't care about
Enumeration<?> entries = zf.entries();
ZipEntry entry = (ZipEntry) entries.nextElement();
InputStream is = zf.getInputStream(entry)
//maybe some other calls to the ZipFile
// do something else
}
My first thought was to do the following with static partial mocking:
final ZipFile test = new ZipFile("path/to/actual.zip");
new NonStrictExpectations() {
#Mocked("(java.io.File)")
ZipFile zf;
{
new ZipFile((File) any); result = test;
}
};
But this won't work as indicated by this line in the tutorial: constructors have void return type, so it makes no sense to record return values for them
My second thought was to try the following:
new NonStrictExpectations() {
{
newInstance("java.util.zip.ZipFile", new File("path/to/actual.zip"));
}
};
But this throws the following when trying to initialize the file:
java.util.zip.ZipException: error in opening zip file
at java.util.zip.ZipFile.open(Native Method)
at java.util.zip.ZipFile.<init>(Unknown Source)
at java.util.zip.ZipFile.<init>(Unknown Source)
My third thought was to use a #MockClass as below:
#Before
public void setUp() throws Exception {
Mockit.setUpMocks(MockedZipFile.class);
}
#After
public void tearDown() {
Mockit.tearDownMocks();
}
#MockClass(realClass=ZipFile.class)
public static class MockedZipFile {
public ZipFile it;
#Mock
public void $init(File f) throws ZipException, IOException {
it = new ZipFile("path/to/actual.zip");//this is what would be called
}
}
But this hoses some other mocks I have that load a configuration file for a different part of my test class. Not to mention I will want different zip files for different test cases.
I suppose I could mocking everything the ZipFile would do, but this would quickly become a giant pain as it's called lots of places, it's output would be need to be mocked, etc, etc. Refactoring to try to make this accessible would be awkward, as the code that uses the ZipFile is internal to the code and the public methods don't really care about it.
I have a feeling there is a way for JMockit to allow this (giving a particular instance of an object when a constructor is called), but I can't figure it out. Does anyone have any ideas?
EDIT: I tried the method suggested by #Rogerio, but I have a new error. Here's my setup:
final ZipFile test = new ZipFile("path/to/actual.zip");
new NonStrictExpectations() {
ZipFile zf;
{
zf.entries();
result = test.entries();
zf.getInputStream((ZipEntry) any);
result = new Delegate() {
InputStream getInputStream(ZipEntry entry) throws IOException {
return test.getInputStream(entry);
}
};
}
};
but I get the following stack trace:
java.lang.InternalError
at path.to.test.ExtractDataTest$1.<init>(ExtractDataTest.java:61)
at path.to.test.ExtractDataTest.setUp(ExtractDataTest.java:61)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
where line 61 is the new NonStrictExpectations() { line.
I really want to say "instead of mocking this object, substitute this other object of the same type". Maybe I have expressed that poorly.
EDIT2: I figured I should include version numbers:
Using Eclipse 3.6.1
Java 1.6.0_26
JMockit 0.999.10
JMockit can mock the ZipFile class, but it interferes with class loading since the JarFile subclass is used by the JVM all the time (whenever it loads a class from a jar file in the classpath). Currently, there is no easy way to avoid this interference (there is a plan to "fix" this, but it will take time).
However, this particular test case isn't very suited for a mocking tool anyway. Instead, I would recommend setting up the test so that it provides an actual zip file with the desired contents in the proper place.
(another edit)
I just applied a change to JMockit (for release 0.999.12) which allows the following test to pass, provided there is a test.zip file in the working dir, and it contains a text file whose first line is "test":
#Test
public void mockZipFile() throws Exception
{
final ZipFile testZip = new ZipFile("test.zip");
new NonStrictExpectations() {
#Capturing #Injectable ZipFile mock;
{
mock.entries(); result = testZip.entries();
mock.getInputStream((ZipEntry) any);
result = new Delegate() {
InputStream delegate(ZipEntry e) throws IOException {
return testZip.getInputStream(e);
}
};
}
};
ZipFile zf = new ZipFile("non-existing");
ZipEntry firstEntry = zf.entries().nextElement();
InputStream content = zf.getInputStream(firstEntry);
String textContent = new BufferedReader(new InputStreamReader(content)).readLine();
assertEquals("test", textContent);
}
However, I would still recommend not using a mocking API for cases like this. Instead, use a real file.
This probably won't help you, but if you were using Mockito or EasyMock, you could add PowerMock, which allows you to mock the construction of new objects in your code under test.
There are two assemblies:
1) Assembly containing serializer. This is a place from where serialization and deserialization starts.
2) Assembly containing serialized types. This is a place which is calling serializer from 1st assembly.
The idea of serializer in assembly1 is simple. It has two methods which are used for conversions of objects from and to byte arrays. The client code for that serializer can look like this:
ISerializer serializer = ...
MyClass my = new MyClass();
byte[] data = serializer.Serialize(my);
Console.WriteLine(Encoding.ASCII.GetString(data)); // dump serialized form
MyClass another = (MyClass)serializer.Deserialize(data);
MyClass is defined in assembly2, so assembly1 knows nothing about it. That scenario will work if serializer is implemented with standard .Net classes, like this:
public class DotNetSerializer : ISerializer
{
public byte[] Serialize(object obj)
{
BinaryFormatter formatter = new BinaryFormatter();
using (MemoryStream stream = new MemoryStream())
{
formatter.Serialize(stream, obj);
byte[] result = stream.GetBuffer();
Array.Resize(ref result, (int)stream.Length);
return result;
}
}
public object Deserialize(byte[] data)
{
BinaryFormatter formatter = new BinaryFormatter();
using (Stream stream = new MemoryStream(data))
{
return formatter.Deserialize(stream);
}
}
}
The serialized form of MyClass will contain information about assembly in which MyClass is defined. However, if serializer will be implemented with usage of Java's classes (converted with IKVM) then there will be ClassNotFound exception thrown during deserialization. This is a serializer implementation using Java classes:
public class JavaSerializer : ISerializer
{
public object Deserialize(byte[] data)
{
ByteArrayInputStream stream = new ByteArrayInputStream(data);
ObjectInputStream ois = new ObjectInputStream(stream);
return ois.readObject();
}
public byte[] Serialize(object obj)
{
ByteArrayOutputStream stream = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(stream);
oos.writeObject(obj);
stream.flush();
return stream.toByteArray();
}
}
This will not work in .Net, but will work normally in Java if loaded from Eclipse with additional entries in plugin manifests such as BuddyPolicy and RegisterBuddy. I can't just switch from JavaSerializer to DotNetSerializer since in my application (which is mostly written in Java) there are lots of readObject,writeObject,readResolve,etc... But I need to fix that problem somehow, so I seeking for solution. Currently I see some hypothetical ways of solution:
Overloading some method of ObjectOutputStream, so serialized form of MyClass will contain assembly name too, like "MyClass, MyAssembly, ...".
Overloading some method in ObjectInputStream, so class will be loaded in some different way, maybe it should be searched in some different assembly, etc.
Adding some information to assemblies manifests so IKVM will know where to search for MyClass.
Is anything of this is real? How this problem should be solved?
The guys from IKVM team gave me the answers:
1) You can subclass ObjectOutputStream
and override annotateClass to write
the assembly name and subclass
ObjectInputStream and override
resolveClass to read the assembly
name.
2) Add the following custom attribute
to the assembly that does the
deserialization: [assembly:
IKVM.Attributes.CustomAssemblyClassLoader(typeof(ikvm.runtime.AppDomainAssemblyClassLoader))]
I also found that I can override classloader for any assembly with explicit setting in application configuration file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="ikvm-classloader:MyExampleAssembly" value="ikvm.runtime.AppDomainAssemblyClassLoader, IKVM.OpenJDK.ClassLibrary, Version=0.37.0.0, Culture=neutral, PublicKeyToken=null" />
</appSettings>
</configuration>
And it also possibly can be set during convertation from java jar when -classloader command line parameter is used.