tags:

views:

39

answers:

2

I have a project where I generate lots of code against many XSD. To keep things separate each set of XSD are bundled together within a project. I have multiple project that will see XSD in resources and generate code against them.

My problem is when I try to access the XSD that are stored in the jar files I cannot get the code to access the XSD from a perticular jar. Instead it will access the first XSD that matches the criterion regardless of the jar.

Here is the code I use to list the ressources, All the jars have the same structure meaning the XSDs are always stored in the xsd folder at the root of the jar file. The code below lists the XSD in the folder.

URL dirURL = clazz.getClassLoader().getResource(path);
  System.out.println(dirURL.toURI());
  if (dirURL != null && dirURL.getProtocol().equals("file")) {
   /* A file path: easy enough */
   System.out.println(dirURL.toURI());
  return new File(dirURL.toURI()).list();
  }

  if (dirURL == null) {
   /* 
    * In case of a jar file, we can't actually find a directory.
    * Have to assume the same jar as clazz.
    */
   String me = clazz.getName().replace(".", "/") + ".class";
   dirURL = clazz.getClassLoader().getResource(me);
   System.out.println(dirURL.toURI());
   System.out.println(me);
  }

  if (dirURL.getProtocol().equals("jar")) {
   /* A JAR path */
   String jarPath = dirURL.getPath().substring(5, dirURL.getPath().indexOf("!")); //strip out only the JAR file
   System.out.println(jarPath);
   JarFile jar = new JarFile(URLDecoder.decode(jarPath, "UTF-8"));
   Enumeration<JarEntry> entries = jar.entries(); //gives ALL entries in jar
   Set<String> result = new HashSet<String>(); //avoid duplicates in case it is a subdirectory
   String name = null;
   while (entries.hasMoreElements()) {
    name = entries.nextElement().getName();
    if (name.startsWith(path)) { //filter according to the path
     String entry = name.substring(path.length());
     int checkSubdir = entry.indexOf("/");
     if (checkSubdir >= 0) {
      // if it is a subdirectory, we just return the directory name
      entry = entry.substring(0, checkSubdir);
     }
     result.add(entry);
    }
   }
   return result.toArray(new String[result.size()]);
A: 

If the XSDs all have the same name, you will need another criteria with knowledge of what the "right one" is. Can you embed some information in it (or with it, like a properties file or something) indicating its purpose?

And, a more convenient iterator to get them might be:

 getClass().getClassLoader().getResources("/file.xsd");

or something. (Relies on the classpath, whether it is on the file system or in a jar)

Nate
my biggest issue here is that I do not have access to the XSD (they are provided so I have to live with them as-is). Also, in many cases, the xsd do have the same name. I thought that by providing a class that I knew was in the same jar file as the desired XSD I would be able to fetch the class loader that had it's hand on that particular jar but to no avail.
Newtopian
A: 

I usually make it a rule to add a resource directory into each JAR with resources that are unique to that JAR held under it. For example (in the Maven structure)

module1/src/main/resources/module1/example.xsd
module2/src/main/resources/module2/example.xsd

The XSDs are then referenced using

InputStream module1XSD= SomeClass.class.getResourceAsStream("/module1/example.xsd");
InputStream module2XSD= SomeClass.class.getResourceAsStream("/module2/example.xsd");

so long as the JARs for module1 and module2 have been placed on the classpath of the application containing SomeClass.

Spring contexts would reference these as

classpath:module1/example.xsd,
classpath:module2/example.xsd

This does mean that you'll have to be able to move the location of XSDs in the JARs that you generate. Maybe even regenerating them through a build script.

Gary Rowe