문제

I have troubles to make loading resources from other jars running. Here is the setup I have

resource.jar  # contains resources I want to load
`-res/hwview/file1

engine.jar    # my application which need resources
`-res/hwview/file2

Interesting thing is that using the code below I'm able to load file2 (which is in the jar I run) but not the file1.

String dir = "res/hwview";
Enumeration<URL> e = getClass().getClassLoader().getResources(dir);
while(e.hasMoreElements()) {
    // prints only file1 from engine.jar 
    // (actually it's in classes directory because I run it from my IDE)
    System.out.println(e.nextElement());
}

[OUTPUT]
/path/to/my/project/SiHwViewUiModel/classes/res/hwview

So I thought maybe the jar was not picked up by the ClassLoader so I printed what was loaded

ClassLoader cl = ClassLoader.getSystemClassLoader();
URL[] urls = ((URLClassLoader)cl).getURLs();
for(URL url: urls){
    System.out.println(url.getFile());
}

[OUTPUT]
/path/to/my/project/SiHwViewUiModel/classes/
/path/to/my/project/Resources/deploy/resources.jar
... and other not so important jars

Any ideas? Thanks for any help!

도움이 되었습니까?

해결책

I found the solution. The problem with getResources() method and similar is that thay cannot be given a directory but only a particular file. This means that if I want to search in the whole classpath for a particular structure I need to create marker file in base directories.

Example: I want to get to my/path directory -> create marker.info (name does not matter) file and then search for it.

resources.jar
`- my/path/
   |- my/directories
   `- marker.info

resources2.jar
`- my/path/
   |- my/other/directories
   `- marker.info

# search
Enumeration<URL> urls = getClass().getClassLoader().getResources("my/path/marker.info"); 

# print
print(urls);
/path/to/resources.jar!/my/path/marker.info
/path/to/resources2.jar!/my/path/marker.info

다른 팁

If the JAR files are on the classpath, you don't need to do anything special. The resources will be found.

If they aren't on the classpath, you need to create a URLClassLoader and use its getResource() method.

In Spring, it can load xml file from all the jar files in the classpath:

ApplicationContext context = new ClassPathXmlApplicationContext(
        "classpath*:**/applicationContext*.xml");

You can check the Spring source to see how Spring achieve that.

public final class JarResource
{
private String jarFileName;
private Map<String, Long> hashSizes = new HashMap<String, Long>();
private Map<String, Object> hashJarContents = new HashMap<String, Object>();

public JarResource(String jarFileName) throws Exception
{
    this.jarFileName = jarFileName;
    ZipFile zipFile = new ZipFile(this.jarFileName);

    Enumeration<ZipEntry> e = (Enumeration<ZipEntry>) zipFile.entries();
    while (e.hasMoreElements())
    {
        ZipEntry zipEntry = e.nextElement();
        if(!zipEntry.isDirectory())
        {
            hashSizes.put(getSimpleName(zipEntry.getName()), zipEntry.getSize());
        }
    }
    zipFile.close();

    // extract resources and put them into the hashMap.
    FileInputStream fis = new FileInputStream(jarFileName);
    BufferedInputStream bis = new BufferedInputStream(fis);
    ZipInputStream zis = new ZipInputStream(bis);
    ZipEntry ze = null;

    while ((ze = zis.getNextEntry()) != null)
    {
        if (ze.isDirectory())
        {
            continue;
        }
        else
        {
            long size = (int) ze.getSize();
            // -1 means unknown size.
            if (size == -1)
            {
                size = hashSizes.get(ze.getName());
            }

            byte[] b = new byte[(int) size];
            int rb = 0;
            int chunk = 0;
            while (((int) size - rb) > 0)
            {
                chunk = zis.read(b, rb, (int) size - rb);
                if (chunk == -1)
                {
                    break;
                }
                rb += chunk;
            }

            hashJarContents.put(ze.getName(), b);
        }
    }
    zis.close();
}

public byte[] getResource(String name)
{
    return (byte[]) hashJarContents.get(name);
}

private String getSimpleName(String entryName)
{
    // Remove ".jar" extension
    int index = entryName.indexOf("/");
    String fileNameWithoutExt = entryName.substring(index, entryName.length());

    return fileNameWithoutExt;
}
}

Then use this class to load your resource:

public static void main(String[] args) throws Exception
{
    JarResource jr = new JarResource("/home/mjiang/Downloads/solr-4.8.0/dist/solr-cell-4.8.0-test.jar");
    byte[] resource = jr.getResource("/META-INF/NOTICE.txt");

    InputStream input = new ByteInputStream(resource, resource.length);

    BufferedReader dis = new BufferedReader(new InputStreamReader(input));

    String line = "";
    while((line = dis.readLine()) != null)
    {
        System.out.println(line);
    }

    dis.close();
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top