Specifying a different plugin for a child project


(Malcolm) #1

So basically I need the parent and all its subprojects to use a particular plugin and one subproject to use a different plugin.
Is this possible?


(James Justinic) #2

Plugins are applied at the project level, not the build level in a multi-project build. While there are certainly some plugins that affect more than just the project that the plugin was applied, this is more of the exception, not the norm.

You didn’t mention any specifics on the plugins you have in mind, so I can only answer that yes, this is definitely possible. However, your exact case is dependent on what the plugin author implemented.


(Malcolm) #3

In my case I am looking to have a parent build file that has a spring boot plugin for 1.5.1 and a sub project that will have a spring boot 1.3.8 plugin.
What I am seeing is that because of the parent plugin of 1.5.1, the boot jar created for the sub project with 1.3.8 plugin is still in the 1.5.1 structure ( with boot-inf/classes and meta-inf at the root). I need the sub project with 1.3.8 plugin to have the boot jar created in the 1.3.8 structure where the classes are at the root level and not under boot-inf.
I have tried applying the 1.3.8 plugin to the sub project and the boot jar on starting up shows 1.3.8 but the boot jar structure is for 1.5.1 and that is something I do not want ( as this impacts certain 3rd party frameworks).


(James Justinic) #4

In that case, I think you’re going to need to look at implementing a custom LayoutFactory with a Layout that overrides the several methods in Layouts$Jar that had BOOT-INF added to them. You’d be dealing directly with Spring classes at that point.

This is a basic classloader ordering problem in that you have two versions of Layouts$Jar on the classpath and the one from 1.5.1 is still winning in the subproject because subprojects inherit their parent’s buildscript classpath. I’d move ahead with 1.5.1 and just implement the custom layout that you actually want (like the 1.3.8 JAR default that you still want never existed).


(Malcolm) #5

Thanks James. I did come across that option abou the custom LayoutFactory but did not find any documentation to explore more details on that. Guess I need to search more.


(James Justinic) #6

I didn’t see much documentation on it either, but I did look at the several classes that were involved in the repackaging layout to see how it was implemented (and what was occurring in your subproject scenario).

This is quick and dirty, but I just threw the following in the build.gradle and it seemed to do what you want. You can probably use this as a starting point.

import org.springframework.boot.loader.tools.Layout
import org.springframework.boot.loader.tools.Layouts
import org.springframework.boot.loader.tools.LayoutFactory
import org.springframework.boot.loader.tools.LibraryScope

class NoBootInfLayoutFactory implements LayoutFactory {

    @Override
    Layout getLayout(File source) {
        if (source?.getName().toLowerCase().endsWith('.jar')) {
            return new Layouts.Jar() {
                @Override
                public String getLibraryDestination(String libraryName, LibraryScope scope) {
                    return "lib/";
                }

                @Override
                public String getRepackagedClassesLocation() {
                    return "";
                }
            };
        }

        return Layouts.forFile(source);
    }
}

springBoot.layoutFactory = new NoBootInfLayoutFactory();

(Malcolm) #7

Thanks. I would never have guessed I need to the add the custom layout code in build.gradle.


(James Justinic) #8

I’m not sure where you added the class originally. In my sample project, I added the class and all the code that I posted directly in my build.gradle file, but I would either put it in buildSrc or create a separate JAR added to your buildscript classpath dependencies in a real project. You can leave it in the build.gradle file, but personally I like to keep buildscripts without imports and only using the DSL.


(Malcolm) #9

Thanks a million James. Your solution worked.


(Malcolm) #10

Facing a new problem now. On executing the boot jar with the custom layout, my boot app is not starting. The loader class is unable to find the dependency classes.

Caused by: java.lang.ClassNotFoundException: org.springframework.boot.SpringApplication
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)


(James Justinic) #11

At this point, you should probably continue the discussion somewhere that is focused on Spring Boot. If you’re changing the layout in the Jar file, I imagine there’s something in the bootstrapping that would need to know about the locations you’re using, but I don’t know enough about the Spring Boot internals to know without researching it from scratch. This is far enough from Gradle now that you probably don’t have an optimal audience here.