google / jimfs

An in-memory file system for Java 7+
Apache License 2.0
2.43k stars 277 forks source link

IllegalAccessException in OSGi. #34

Open benson-basis opened 8 years ago

benson-basis commented 8 years ago

If I try to call the Jimfs via Paths.get of a Jimfs URI inside an OSGi bundle, I get an illegal access exception from the reflection code in the file system provider. I'm not sure what the fuss is about: this is a pax-exam osgi test that uses Jimfs, and it so all the Jimfs stuff should be in one class loader: the class loader for the jimfs bundle.

In the debugger, toPath.getClass().getClassLoader() is null. fileSystem.getClass().getClassLoader() is org.eclipse.osgi.internal.loader.EquinoxClassLoader@1437268e[com.google.jimfs:1.1.0(id=37)] -- the jimfs bundle.

I see; the collection of file systems in the main 'Paths' class are all loaded by the app class loader, so we're using SystemJimfsClassLoader from the wrong class loader.

Perhaps this is just a typical 'OSGi versus SPI' problem?


Class sun.reflect.Reflection can not access a member of class com.google.common.jimfs.JimfsFileSystem with modifiers "public"

"main@1" prio=5 tid=0x1 nid=NA runnable
  java.lang.Thread.State: RUNNABLE
      at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:109)
      at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:261)
      at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:253)
      at java.lang.reflect.Method.invoke(Method.java:599)
      at com.google.common.jimfs.SystemJimfsFileSystemProvider.toPath(SystemJimfsFileSystemProvider.java:179)
      at com.google.common.jimfs.SystemJimfsFileSystemProvider.getPath(SystemJimfsFileSystemProvider.java:144)
      at java.nio.file.Paths.get(Paths.java:143)
      at com.basistech.rosette.osgi.util.NioPathDeserializer.deserialize(NioPathDeserializer.java:42)
      at com.basistech.rosette.osgi.util.NioPathDeserializer.deserialize(NioPathDeserializer.java:31)
      at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:490)
      at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:95)
      at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:260)
      at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:125)
      at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3789)
      at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2798)
      at com.basistech.rosette.osgi.util.OsgiUtils.deserializeYamlConfiguration(OsgiUtils.java:116)
      at com.basistech.rosette.osgi.util.AbstractComponentService.createFactory(AbstractComponentService.java:47)
benson-basis commented 8 years ago

See https://shomeier.wordpress.com/2015/03/01/implementing-a-filesystemprovider-in-an-osgi-compliant-manner/ for a discussion of this issue.

benson-basis commented 8 years ago

Maybe this amounts to an opportunity for doc.

cgdecker commented 8 years ago

Hmm... I wonder if making JimfsFileSystem public would fix this issue. SystemJimfsFileSystemProvider is actually intended to fix problems that arise in multiple classloader environments like this, but it looks like the security manager isn't allowing JimfsFileSystem.toPath(URI) to be invoked (presumably because it's a public method on a package-private class, and also not part of the FileSystem interface).

benson-basis commented 8 years ago

It looks to me as if the FileSystemProviders is just another one of those Java 'global' mechanisms that messes up (with) OSGi. Adding your package to the system bundle works just fine. I haven't looked into whether ServiceMix has done something in this area. I made a PR, as you've undoubtedly seen, with some doc. However, your remark about package-private suggests that it could work. I could make a pax-exam test in a PR to demonstrate this and try the fix if you like.

jonnybot0 commented 2 years ago

So, I've had a related problem which I commented about here: https://github.com/google/jimfs/issues/7#issuecomment-1244373117

My issue is that I can create a JIMFS virtual filesystem in my little OSGi bundle just fine, but anytime something tries to access one of the files via a jimfs:// URI, it fails, thinking that the JIMFS URL Handler isn't installed.

The reason for my problem is that Java's Paths.get (called in PathURLConnection#connect) tries to load the URL handler from the system classloader (via ServiceLoader.load(FileSystemProvider.class, ClassLoader.getSystemClassLoader()) in FileSystemProvider#loadInstalledProviders). However, Jimfs registered its handler in my Bundle's classloader, as it probably should.

I've been mulling over the best approach to solving the problem. I reckon it's probably to rewrite PathURLConnection and Handler to have some knowledge about the classloader they're registered with. That's tricky, though. I can't simply call ServiceLoader.load(FileSystemProvider.class, SystemJimfsFileSystemProvider.class.getClassLoader()), as that still tries to load and instantiate other FileSystemProviders like com.sun.nio.zipfs.ZipFileSystemProvider, which, annoyingly, are only visible to the system classloader in the particular OSGi walled garden I get to play in.

Would happily accept some pointers from @cpovirk or @cgdecker if there's a rough direction you'd like to take this but haven't got the time at the moment. I went ahead and signed the contributor agreement.

Feel free to tell me this isn't the same issue & I should get my own thread, but this seems closely enough related that I wanted to note it here.