0

Spring Boot Maven Plugin. LayoutFactory new feature. Available since 1.5.0.M1.

I am having problems when I define a custom launcher in the Custom Layout:

@Override public String getLauncherClassName() { return "com.mycompany.CustomLauncher"; }

If I include my custom launcher in the boot application sources, it gets repackaged to BOOT-INF/classes, and when I try to run the JAR it fails with a ClassNotFound exception.

I have been reading the Repackager code but I cannot find any hook that allows to selectively exclude a given class from the repackaging sequence. If I override the getRepackagedClassesLocation method in my layout then the boot main class is loaded by a different classloader and it fails on SpringBoot ClassNotFound.

Is there any way that I can force the launcher out of the BOOT-INF/classes repackaging?

UPDATE 1

@Override
public void writeLoadedClasses(LoaderClassesWriter writer) throws IOException
{
    String name = PropertiesLauncherInternal.class.getName().replaceAll("\\.", "\\\\") + ".class";
    InputStream inputStream = PropertiesLauncherInternal.class.getResourceAsStream(PropertiesLauncherInternal.class.getSimpleName() + ".class");
    writer.writeEntry(name, inputStream);
    writer.writeLoaderClasses();
}

In order to see that the code is accessible I have added this test:

    JarInputStream is = new JarInputStream(new FileInputStream(new File("c:/git/dev/framework/boot/target/boot-current-SNAPSHOT.jar")), true);
    JarEntry entry = null;
    while (null != (entry = is.getNextJarEntry()))
    {
        System.out.println(entry.getName() + "-" + entry.getCrc());
    }

    URL url = new File("c:/git/dev/framework/boot/target/boot-current-SNAPSHOT.jar").toURL();
    URL[] urls = new URL[] { url };
    ClassLoader cl = new URLClassLoader(urls);
    Class cls = cl.loadClass("com.test.Boot");
    Class cls = cl.loadClass("com.launcher.PropertiesLauncherInternal");

For the first loop I get the following log:

BOOT-INF/--1
BOOT-INF/classes/--1
BOOT-INF/classes/com/-0
BOOT-INF/classes/com/test/-0
BOOT-INF/classes/com/test/Boot.class-2405822989
...
com\launcher\PropertiesLauncherInternal.class--1

The number next to the class names are the CRC. I am not sure whether is relevant, but the CRC-32 is unknown.

When using the classloader, I am able to load com.test.Boot but it fails on ClassNotFoundException for the PropertiesLauncherInternal.class

1 Answers1

0

Rather than having it alongside your application code, your launcher code should be in a separate module that's declared as a dependency of Spring Boot's Maven plugin. This separate module should use Maven's standard jar packaging and shouldn't be repackaged using Spring Boot's Maven plugin.

There's a sample that shows how to set things up.

Andy Wilkinson
  • 108,729
  • 24
  • 257
  • 242
  • Hi Andy, I've tried doing that and I get my launcher packed. However, when I try to run the JAR I get a **Error: Could not find or load main class**. If I copy the same class (identical content, same name) to the same location in the JAR manually, then it works. Any idea what the problem might be? – Juan José Roldan Jan 25 '17 at 10:25
  • No, sorry. Perhaps you can share some code that reproduces the problem? – Andy Wilkinson Jan 25 '17 at 11:28
  • I have added some details on the original question. – Juan José Roldan Jan 25 '17 at 13:22
  • The problem was the way I used the wrong slash conversion. The JAR was built, the resource could be found but the classloader was unable to load it. – Juan José Roldan Jan 25 '17 at 16:02