2

I have a case where I am loading a string template group from a file contained in a jar. This works fine using the following mechanism:

final String urlName = new StringBuilder()
            .append("jar:file:").append(templateJar.getAbsolutePath()).append("!")
            .append(templateFileName).toString();
final URL url;
try {
        url = new URL(urlName);
} catch (MalformedURLException ex) {
        throw new GeneratorException("bad manifest url", ex);
}
final STGroup stg = new STGroupFile(url, "US-ASCII", '<', '>');

The difficulty comes in when the template file contains an

...
import "../../dataTypeMaps.stg"
...

String template fails with the following:

can't load group file jar:file:/home/phreed/.m2/repository/edu/vanderbilt/isis/druid/druid-template/2.0.0/druid-template-2.0.0.jar!/template/src/main/java/sponsor/orm/ContractCreator.stg
Caused by: java.lang.IllegalArgumentException: No such group file: ../../dataTypeMaps.stg
    at org.stringtemplate.v4.STGroupFile.<init>(STGroupFile.java:69)
    at org.stringtemplate.v4.STGroup.importTemplates(STGroup.java:570)
    at org.stringtemplate.v4.compiler.GroupParser.group(GroupParser.java:199)
    at org.stringtemplate.v4.STGroup.loadGroupFile(STGroup.java:619)
    at org.stringtemplate.v4.STGroupFile.load(STGroupFile.java:139)
    at org.stringtemplate.v4.STGroupFile.load(STGroupFile.java:128)
    at org.stringtemplate.v4.STGroup.lookupTemplate(STGroup.java:237)
    at org.stringtemplate.v4.STGroup.getInstanceOf(STGroup.java:172)
    at edu.vanderbilt.isis.druid.generator.Generator.build(Generator.java:215)
    at edu.vanderbilt.isis.druid.generator.DruidMojo.execute(DruidMojo.java:193)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:101)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:209)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:84)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:59)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.singleThreadedBuild(LifecycleStarter.java:183)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:161)
    at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:320)
    at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:156)
    at org.apache.maven.cli.MavenCli.execute(MavenCli.java:537)
    at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:196)
    at org.apache.maven.cli.MavenCli.main(MavenCli.java:141)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:290)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:230)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:409)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:352)

Is it possible to set things up with the jar so that the import will work? The above approach works fine when there is no jar involved.

phreed
  • 1,759
  • 1
  • 15
  • 30

3 Answers3

1

The simple answer is that the path to the imported file is wrong

...
import "dataTypeMaps.stg"
...

The import will cause the file to be looked for starting at the root of the jar. The above import would amount to the file being placed at...

final String urlName = new StringBuilder()
        .append("jar:file:").append(templateJar.getAbsolutePath()).append("!")
        .append("dataTypeMaps.stg").toString();

Why the behavior is different than when the template group file is on the native file system I do not know. In order to get this to work I changed the classpath to include the jar file. As this was done in the context of a Maven plugin, the plugin needs to change the classpath dynamically. This was done with the following code...

 public void setTemplateJarName(String templateJarName) throws GeneratorException {
    this.templateJarName = templateJarName;
    final Thread ct = Thread.currentThread();
    final ClassLoader pcl = ct.getContextClassLoader();
    URL[] nurl;
    try {
        nurl = new URL[]{ new URL("file://"+templateJarName) };
    } catch (MalformedURLException ex) {
        throw new GeneratorException("could not load template jar", ex);
    }
    final URLClassLoader ucl = new URLClassLoader(nurl, pcl);
    ct.setContextClassLoader(ucl);
}
phreed
  • 1,759
  • 1
  • 15
  • 30
1
  1. Double check your templates are really in your jar.
  2. Use the following code :

If the templates are dispatched in a tree like this:

/-->resources
   +--> c/     (many .st and .stg files)
   +--> cpp/   (many .st and .stg files)
   +--> java/  (many .st and .stg files)
   +--> c.stg
   +--> cpp.stg
   +--> java.stg

The content of java.stg is:

group Java;

import "java"

doNothing() ::= <<>>

To load all the files in one call :

URL     url   = getClass().getResource( "/resources/" + templateName );
STGroup group = new STGroupFile( url, "utf-8", '<', '>' );

In my case templateName equals c.stg, cpp.stg or java.stg.

Aubin
  • 14,617
  • 9
  • 61
  • 84
0

The relative path only works on the file system. If you want to import a template from the classpath, use the fully qualified name. This is the same, as when you would load the file from the classpath yourself, using Class::getResource(). Using the fully qualified name, also works for the filesystem.

So, assuming there are two template files:

  • src/main/resources/util/date.stg
  • src/main/resources/generator/class.stg

Then in class.stg you use the fully qualified name:

import "util/date.stg"
Arco Oost
  • 221
  • 1
  • 3