Maven 2.x GWT Plugin

Plugin attempts to compile projects with 'pom' packaging

Details

  • Type: Bug Bug
  • Status: Closed Closed
  • Priority: Minor Minor
  • Resolution: Fixed
  • Affects Version/s: 2.1.0
  • Fix Version/s: 1.2
  • Component/s: None
  • Labels:
    None
  • Environment:
    Fedora 11, Java 1.6.0_16, Maven 2.2.1, GWT 1.7.1
  • Number of attachments :
    0

Description

When the GWT compile goal is enabled for projects which have the 'pom' packaging type, maven attempts to compile the project and fails because no source code is available. The compilation should be disabled by default for projects which have the 'pom' packaging type.

Activity

Hide
nicolas de loof added a comment -

Committed revision 11297.

Show
nicolas de loof added a comment - Committed revision 11297.
Hide
Richard Allen added a comment -

Sometimes you want to run a GWT compile with a pom project. We use a pom project to establish a muti-module build and create a WAR using the maven-assembly-plugin. A full explanation of why we do this is detailed, but this is something Maven readily supports, so the gwt-maven-plugin should support it also. I now have to patch the gwt-maven-plugin because the fix for this issue breaks our build.

Show
Richard Allen added a comment - Sometimes you want to run a GWT compile with a pom project. We use a pom project to establish a muti-module build and create a WAR using the maven-assembly-plugin. A full explanation of why we do this is detailed, but this is something Maven readily supports, so the gwt-maven-plugin should support it also. I now have to patch the gwt-maven-plugin because the fix for this issue breaks our build.
Hide
Daniel Scott added a comment -

Sorry, I don't really understand this. If your parent project contains source code, then it should not be of type 'pom'.

We have what sounds like a similar structure to you, a parent project, which contains no source code, with children which are all gwt projects/libraries. A 'mvn compile' in the parent should compile all of the children, but not the parent itself. If the parent does contain its own source code, then it should be defined as a 'war' or 'jar' project.

Am I misunderstanding something?

Show
Daniel Scott added a comment - Sorry, I don't really understand this. If your parent project contains source code, then it should not be of type 'pom'. We have what sounds like a similar structure to you, a parent project, which contains no source code, with children which are all gwt projects/libraries. A 'mvn compile' in the parent should compile all of the children, but not the parent itself. If the parent does contain its own source code, then it should be defined as a 'war' or 'jar' project. Am I misunderstanding something?
Hide
Richard Allen added a comment -

To elaborate on my previous comment, a pom project does not need source code to run a GWT compile. In our case, the pom project builds a war directory, we configure gwt-maven-plugin to use that war directory, and give gwt-maven-plugin a GWT module to compile. The specified GWT module is on the classpath, so the GWT compiler successfully finds it and compiles it into the war directory of the pom project. This configuration provides lots of flexibility for a multi-module project. Before this fix, this configuration works beautifully.

Show
Richard Allen added a comment - To elaborate on my previous comment, a pom project does not need source code to run a GWT compile. In our case, the pom project builds a war directory, we configure gwt-maven-plugin to use that war directory, and give gwt-maven-plugin a GWT module to compile. The specified GWT module is on the classpath, so the GWT compiler successfully finds it and compiles it into the war directory of the pom project. This configuration provides lots of flexibility for a multi-module project. Before this fix, this configuration works beautifully.
Hide
nicolas de loof added a comment -

Beeing possible using some assembly plugin hacking does not mean this is a supported feature. The supported way to build WAR is to use the ware packaging

Please describe your use case and we could consider some improvements or doc upgrades, but a POM project is (by design) NOT supposed to contain Java source code

Show
nicolas de loof added a comment - Beeing possible using some assembly plugin hacking does not mean this is a supported feature. The supported way to build WAR is to use the ware packaging Please describe your use case and we could consider some improvements or doc upgrades, but a POM project is (by design) NOT supposed to contain Java source code
Hide
Richard Allen added a comment -

A pom project does not have to be a parent project. In our case, we use the maven-assembly-plugin to create the war file. The maven reactor makes sure that parents get built before children, therefore, if the project that executed the assembly were a parent of projects that must go into the assembly, then it would fail, because the parent would be built before the children. The solution to this is to make the project that executes the assembly a leaf project. Then you can be certain the projects specified in <modules> get built before the assembly.

This arrangement allows us to divide a large war into multiple projects, many which supply src/main/webapp (WAR type) resources. I believe many people use the maven-war-plugin war overlay functionality to merge multiple war projects (*.war files). The problem we found with this approach is that it is very slow because it must build a war file for each war project, then extract each of those war files when merging into the final war. Using our approach, the build takes only a fraction of the time it does with the maven-war-plugin overlay approach.

Show
Richard Allen added a comment - A pom project does not have to be a parent project. In our case, we use the maven-assembly-plugin to create the war file. The maven reactor makes sure that parents get built before children, therefore, if the project that executed the assembly were a parent of projects that must go into the assembly, then it would fail, because the parent would be built before the children. The solution to this is to make the project that executes the assembly a leaf project. Then you can be certain the projects specified in <modules> get built before the assembly. This arrangement allows us to divide a large war into multiple projects, many which supply src/main/webapp (WAR type) resources. I believe many people use the maven-war-plugin war overlay functionality to merge multiple war projects (*.war files). The problem we found with this approach is that it is very slow because it must build a war file for each war project, then extract each of those war files when merging into the final war. Using our approach, the build takes only a fraction of the time it does with the maven-war-plugin overlay approach.
Hide
Richard Allen added a comment -

An added benefit from our approach, is that I have been able to get all of my multiple projects on the GWT DevMode classpath without using the build-helper-maven-plugin hack described here: http://mojo.codehaus.org/gwt-maven-plugin/user-guide/productivity.html.

My pom project that builds the war has <modules>, so the source directories for the multiple projects are known to Maven. All I had to do was add the following variable to RunMojo:

/**
 * If the executed project is a reactor project,
 * this will contains the full list of projects in the reactor.
 *
 * @parameter expression="${reactorProjects}"
 * @required
 * @readonly
 */
protected List<MavenProject> reactorProjects;

and add the following code to RunMojo.doExecute() after the JavaCommand is instantiated:

if (reactorProjects != null) {
    for (MavenProject project : reactorProjects) {
        List<String> compileSourceRoots = project.getCompileSourceRoots();
        for (String srcRoot : compileSourceRoots) {
            File srcRootFile = new File(srcRoot);
            if (srcRootFile.isDirectory()) {
                getLog().info("Adding compile source to classpath: "
                        + srcRootFile.getPath());
                cmd.withinClasspathFirst(srcRootFile);
            }
        }

        List<Resource> compileResources = project.getBuild().getResources();
        for (Resource resource : compileResources) {
            File resourceRootFile = new File(resource.getDirectory());
            if (resourceRootFile.isDirectory()) {
                getLog().info("Adding compile resource to classpath: "
                        + resourceRootFile.getPath());
                cmd.withinClasspathFirst(resourceRootFile);
            }
        }

        File webappSourceRootFile = new File(project.getBasedir(), "src/main/webapp");
        if (webappSourceRootFile.isDirectory()) {
            getLog().info("Adding webapp resource to classpath: "
                    + webappSourceRootFile.getPath());
            cmd.withinClasspathFirst(webappSourceRootFile);
        }
    }
}

You may call this all a "hack", but it makes our development environment significantly more productive, easier to configure via Maven, and easier to maintain.

Show
Richard Allen added a comment - An added benefit from our approach, is that I have been able to get all of my multiple projects on the GWT DevMode classpath without using the build-helper-maven-plugin hack described here: http://mojo.codehaus.org/gwt-maven-plugin/user-guide/productivity.html. My pom project that builds the war has <modules>, so the source directories for the multiple projects are known to Maven. All I had to do was add the following variable to RunMojo:
/**
 * If the executed project is a reactor project,
 * this will contains the full list of projects in the reactor.
 *
 * @parameter expression="${reactorProjects}"
 * @required
 * @readonly
 */
protected List<MavenProject> reactorProjects;
and add the following code to RunMojo.doExecute() after the JavaCommand is instantiated:
if (reactorProjects != null) {
    for (MavenProject project : reactorProjects) {
        List<String> compileSourceRoots = project.getCompileSourceRoots();
        for (String srcRoot : compileSourceRoots) {
            File srcRootFile = new File(srcRoot);
            if (srcRootFile.isDirectory()) {
                getLog().info("Adding compile source to classpath: "
                        + srcRootFile.getPath());
                cmd.withinClasspathFirst(srcRootFile);
            }
        }

        List<Resource> compileResources = project.getBuild().getResources();
        for (Resource resource : compileResources) {
            File resourceRootFile = new File(resource.getDirectory());
            if (resourceRootFile.isDirectory()) {
                getLog().info("Adding compile resource to classpath: "
                        + resourceRootFile.getPath());
                cmd.withinClasspathFirst(resourceRootFile);
            }
        }

        File webappSourceRootFile = new File(project.getBasedir(), "src/main/webapp");
        if (webappSourceRootFile.isDirectory()) {
            getLog().info("Adding webapp resource to classpath: "
                    + webappSourceRootFile.getPath());
            cmd.withinClasspathFirst(webappSourceRootFile);
        }
    }
}
You may call this all a "hack", but it makes our development environment significantly more productive, easier to configure via Maven, and easier to maintain.
Hide
Daniel Scott added a comment -

Sorry, this still doesn't make much sense to me:

1. If your dependency (src/main/webapp) files are just normal resources (HTML/CSS/JS etc) then they don't need to be in a war project at all, you can just copy them into the right place.
2. If your dependency is java code, then you can just put it into a jar file and then include this as a dependency in the war project.

Is there a particular reason why you need 'library' wars? I didn't think that wars were supposed to be used in this way.

Show
Daniel Scott added a comment - Sorry, this still doesn't make much sense to me: 1. If your dependency (src/main/webapp) files are just normal resources (HTML/CSS/JS etc) then they don't need to be in a war project at all, you can just copy them into the right place. 2. If your dependency is java code, then you can just put it into a jar file and then include this as a dependency in the war project. Is there a particular reason why you need 'library' wars? I didn't think that wars were supposed to be used in this way.
Hide
nicolas de loof added a comment -

m2eclipse will automatically handle this for you. No idea about how other IDEs will. As you say, the "hack" is only a hack, and we CAN'T support hacks as features.

Show
nicolas de loof added a comment - m2eclipse will automatically handle this for you. No idea about how other IDEs will. As you say, the "hack" is only a hack, and we CAN'T support hacks as features.
Hide
Richard Allen added a comment - - edited

@nicolas: I'm surprised you consider executing a maven plugin from a pom project a "hack". Maven was designed to make that possible.

@Daniel: The following is a very shortened version of our project structure. It provides for very good sharing of code between projects. Both project1 and project2 are web applications (they compose .war files). The projects under the apps/ directories are Java WebStart apps that communicate with the web application. The projects under the modules/ directories are projects with a WAR structure (portions of the overall WAR), which we once used the maven-war-plugin to overlay on top of another war project to form the final war file (e.g., project1.war and project2.war). Now we use the pom project in the webapp/ directories to assemble the project. We copy the src/main/webapp directory as you suggested. The resulting JAR (src/main/resources and src/main/java) from the modules projects end up in WEB-INF/lib. It's much more flexible, and much faster.

pom/
|- pom.xml (pom parent for all projects)
|
common/
|- pom.xml (pom parent for common projects)
|
|- util/
|  |- pom.xml (jar project with common utility code)
|  |- src/main/resources
|  \- src/main/java
|
|- app/
|  |- pom.xml (jar project with common domain code)
|  |- src/main/resources
|  \- src/main/java
|
|- web/
|  |- pom.xml (jar project with common JEE code)
|  |- src/main/resources
|  \- src/main/java
|
|- gwt/
|  |- pom.xml (jar project with common GWT widgets)
|  |- src/main/resources
|  \- src/main/java
|
modules/
|- pom.xml (pom parent for common web modules - WAR projects)
|
|- common-feature1-module/
|  |- pom.xml (war type project)
|  |- src/main/resources
|  |- src/main/java
|  \- src/main/webapp
|
|- common-feature2-module/
|  |- pom.xml (war type project)
|  |- src/main/resources
|  |- src/main/java
|  \- src/main/webapp
|
project1/
|- pom.xml (pom parent for project1)
|
|- common/
|  |- pom.xml (pom parent for project1 common JAR projects)
|  |
|  |- app/
|  |  |- pom.xml (jar project with project1 common domain code)
|  |  |- src/main/resources
|  |  \- src/main/java
|  |
|  |- web/
|  |  |- pom.xml (jar project with project1 common JEE code)
|  |  |- src/main/resources
|  |  \- src/main/java
|  |
|  \- gwt/
|     |- pom.xml (jar project with project1 common GWT widgets)
|     |- src/main/resources
|     \- src/main/java
|   
|- apps/
|  |- pom.xml (pom parent for project1 WebStart application projects)
|  |
|  |- project1-app1/
|  |  |- pom.xml (jar project - Java WebStart application)
|  |  |- src/main/resources
|  |  \- src/main/java
|  |
|  \- project1-app2/
|     |- pom.xml (jar project - Java WebStart application)
|     |- src/main/resources
|     \- src/main/java
|
|- modules/
|  |- pom.xml (pom parent for project1 web modules - WAR projects)
|  |
|  |- project1-feature1-module/
|  |  |- pom.xml (war type project)
|  |  |- src/main/resources
|  |  |- src/main/java
|  |  \- src/main/webapp
|  |
|  \- project1-feature2-module/
|     |- pom.xml (war type project)
|     |- src/main/resources
|     |- src/main/java
|     \- src/main/webapp
|   
|- webapp/
|  \- pom.xml (pom project with <modules> to build project1.war)
|
project2/
|- pom.xml (pom parent for project2)
|
|- common/
|  |- pom.xml (pom parent for project2 common JAR projects)
|  |
|  |- app/
|  |  |- pom.xml (jar project with project2 common domain code)
|  |  |- src/main/resources
|  |  \- src/main/java
|  |
|  |- web/
|  |  |- pom.xml (jar project with project2 common JEE code)
|  |  |- src/main/resources
|  |  \- src/main/java
|  |
|  \- gwt/
|     |- pom.xml (jar project with project2 common GWT widgets)
|     |- src/main/resources
|     \- src/main/java
|   
|- apps/
|  |- pom.xml (pom parent for project2 WebStart application projects)
|  |
|  |- project2-app1/
|  |  |- pom.xml (jar project - Java WebStart application)
|  |  |- src/main/resources
|  |  \- src/main/java
|  |
|  \- project2-app2/
|     |- pom.xml (jar project - Java WebStart application)
|     |- src/main/resources
|     \- src/main/java
|
|- modules/
|  |- pom.xml (pom parent for project2 web modules - WAR projects)
|  |
|  |- project2-feature1-module/
|  |  |- pom.xml (war type project)
|  |  |- src/main/resources
|  |  |- src/main/java
|  |  \- src/main/webapp
|  |
|  \- project2-feature2-module/
|     |- pom.xml (war type project)
|     |- src/main/resources
|     |- src/main/java
|     \- src/main/webapp
|   
|- webapp/
|  \- pom.xml (pom project with <modules> to build project2.war)
|
...
Show
Richard Allen added a comment - - edited @nicolas: I'm surprised you consider executing a maven plugin from a pom project a "hack". Maven was designed to make that possible. @Daniel: The following is a very shortened version of our project structure. It provides for very good sharing of code between projects. Both project1 and project2 are web applications (they compose .war files). The projects under the apps/ directories are Java WebStart apps that communicate with the web application. The projects under the modules/ directories are projects with a WAR structure (portions of the overall WAR), which we once used the maven-war-plugin to overlay on top of another war project to form the final war file (e.g., project1.war and project2.war). Now we use the pom project in the webapp/ directories to assemble the project. We copy the src/main/webapp directory as you suggested. The resulting JAR (src/main/resources and src/main/java) from the modules projects end up in WEB-INF/lib. It's much more flexible, and much faster.
pom/
|- pom.xml (pom parent for all projects)
|
common/
|- pom.xml (pom parent for common projects)
|
|- util/
|  |- pom.xml (jar project with common utility code)
|  |- src/main/resources
|  \- src/main/java
|
|- app/
|  |- pom.xml (jar project with common domain code)
|  |- src/main/resources
|  \- src/main/java
|
|- web/
|  |- pom.xml (jar project with common JEE code)
|  |- src/main/resources
|  \- src/main/java
|
|- gwt/
|  |- pom.xml (jar project with common GWT widgets)
|  |- src/main/resources
|  \- src/main/java
|
modules/
|- pom.xml (pom parent for common web modules - WAR projects)
|
|- common-feature1-module/
|  |- pom.xml (war type project)
|  |- src/main/resources
|  |- src/main/java
|  \- src/main/webapp
|
|- common-feature2-module/
|  |- pom.xml (war type project)
|  |- src/main/resources
|  |- src/main/java
|  \- src/main/webapp
|
project1/
|- pom.xml (pom parent for project1)
|
|- common/
|  |- pom.xml (pom parent for project1 common JAR projects)
|  |
|  |- app/
|  |  |- pom.xml (jar project with project1 common domain code)
|  |  |- src/main/resources
|  |  \- src/main/java
|  |
|  |- web/
|  |  |- pom.xml (jar project with project1 common JEE code)
|  |  |- src/main/resources
|  |  \- src/main/java
|  |
|  \- gwt/
|     |- pom.xml (jar project with project1 common GWT widgets)
|     |- src/main/resources
|     \- src/main/java
|   
|- apps/
|  |- pom.xml (pom parent for project1 WebStart application projects)
|  |
|  |- project1-app1/
|  |  |- pom.xml (jar project - Java WebStart application)
|  |  |- src/main/resources
|  |  \- src/main/java
|  |
|  \- project1-app2/
|     |- pom.xml (jar project - Java WebStart application)
|     |- src/main/resources
|     \- src/main/java
|
|- modules/
|  |- pom.xml (pom parent for project1 web modules - WAR projects)
|  |
|  |- project1-feature1-module/
|  |  |- pom.xml (war type project)
|  |  |- src/main/resources
|  |  |- src/main/java
|  |  \- src/main/webapp
|  |
|  \- project1-feature2-module/
|     |- pom.xml (war type project)
|     |- src/main/resources
|     |- src/main/java
|     \- src/main/webapp
|   
|- webapp/
|  \- pom.xml (pom project with <modules> to build project1.war)
|
project2/
|- pom.xml (pom parent for project2)
|
|- common/
|  |- pom.xml (pom parent for project2 common JAR projects)
|  |
|  |- app/
|  |  |- pom.xml (jar project with project2 common domain code)
|  |  |- src/main/resources
|  |  \- src/main/java
|  |
|  |- web/
|  |  |- pom.xml (jar project with project2 common JEE code)
|  |  |- src/main/resources
|  |  \- src/main/java
|  |
|  \- gwt/
|     |- pom.xml (jar project with project2 common GWT widgets)
|     |- src/main/resources
|     \- src/main/java
|   
|- apps/
|  |- pom.xml (pom parent for project2 WebStart application projects)
|  |
|  |- project2-app1/
|  |  |- pom.xml (jar project - Java WebStart application)
|  |  |- src/main/resources
|  |  \- src/main/java
|  |
|  \- project2-app2/
|     |- pom.xml (jar project - Java WebStart application)
|     |- src/main/resources
|     \- src/main/java
|
|- modules/
|  |- pom.xml (pom parent for project2 web modules - WAR projects)
|  |
|  |- project2-feature1-module/
|  |  |- pom.xml (war type project)
|  |  |- src/main/resources
|  |  |- src/main/java
|  |  \- src/main/webapp
|  |
|  \- project2-feature2-module/
|     |- pom.xml (war type project)
|     |- src/main/resources
|     |- src/main/java
|     \- src/main/webapp
|   
|- webapp/
|  \- pom.xml (pom project with <modules> to build project2.war)
|
...
Hide
Daniel Scott added a comment - - edited

OK, thanks for that, now I can see how your code is structured. I still don't see where you have a 'pom' project which contains source code (Directly, not in a submodule). 'apps', 'modules' and 'webapp' are just containers for other projects, so they do not need compilation themselves, they just need to compile their children.

I don't understand your comment to nicolas either (Maybe I'm having a bad day ). I don't think he's suggesting that. It's perfectly reasonable to execute 'mvn:compile' in your 'apps', 'modules' and 'webapp' directories, all that should happen is that the compile target is passed on to the children, it should not attempt to compile 'apps/src/main/java'.

Show
Daniel Scott added a comment - - edited OK, thanks for that, now I can see how your code is structured. I still don't see where you have a 'pom' project which contains source code (Directly, not in a submodule). 'apps', 'modules' and 'webapp' are just containers for other projects, so they do not need compilation themselves, they just need to compile their children. I don't understand your comment to nicolas either (Maybe I'm having a bad day ). I don't think he's suggesting that. It's perfectly reasonable to execute 'mvn:compile' in your 'apps', 'modules' and 'webapp' directories, all that should happen is that the compile target is passed on to the children, it should not attempt to compile 'apps/src/main/java'.
Hide
Richard Allen added a comment -

As I mentioned in an earlier comment, we don't have source under a pom project, so you are correct in not seeing that.

Because the webapp/ project assembles the war directory, it doesn't make sense in our case to perform a GWT compile before then (before the war directory is assembled). As I'm sure you are aware, GWT compiles the code into one big single page application. In our case, GWT code comes from any number of projects that are part of the Maven multi-module build. Running GWT compile on those sub-projects would create invalid results. To create a valid result (GWT application), GWT must compile the entire project at one time. Additionally, GWT compile only cares that the GWT modules it is looking for are on the classpath, which Maven dependency management takes care of.

Show
Richard Allen added a comment - As I mentioned in an earlier comment, we don't have source under a pom project, so you are correct in not seeing that. Because the webapp/ project assembles the war directory, it doesn't make sense in our case to perform a GWT compile before then (before the war directory is assembled). As I'm sure you are aware, GWT compiles the code into one big single page application. In our case, GWT code comes from any number of projects that are part of the Maven multi-module build. Running GWT compile on those sub-projects would create invalid results. To create a valid result (GWT application), GWT must compile the entire project at one time. Additionally, GWT compile only cares that the GWT modules it is looking for are on the classpath, which Maven dependency management takes care of.
Hide
Daniel Scott added a comment - - edited

In which project is the final war assembled? Is it webapp? Why can't this project be a 'war'?

Let me see if I have this right. During your build, you copy code from various other modules into the webapp/war directory and then run a GWT compile on the whole lot? That sounds like a fragile way to do things.

You say that "Running GWT compile on those sub-projects would create invalid results". In this case, these should be jar projects and included as jars in the war. You can include the java source within the jar for the final 'GWT compile' at the end.

Show
Daniel Scott added a comment - - edited In which project is the final war assembled? Is it webapp? Why can't this project be a 'war'? Let me see if I have this right. During your build, you copy code from various other modules into the webapp/war directory and then run a GWT compile on the whole lot? That sounds like a fragile way to do things. You say that "Running GWT compile on those sub-projects would create invalid results". In this case, these should be jar projects and included as jars in the war. You can include the java source within the jar for the final 'GWT compile' at the end.
Hide
Richard Allen added a comment - - edited

First, understand that we are already using a customized gwt-maven-plugin to work around this issue, an issue related to a comment I made on MGWT-75, and to put the source for the projects in the reactor (i.e., the listed <module> s) on the classpath for GWT 2.0 Development Mode without having to list the directories using build-helper-maven-plugin (i.e., less configuration, easier to maintain). Therefore, if you are set against allowing GWT compile to be used with pom projects, so be it, it's not slowing us down. As an effort to contribute back to the community, I commented on this issue to help you and others that might use your plugin.

However, I find it odd that you would rather restrict the use of your plugin to specific use cases then simply adjust your fix to make it an option – chosen by default if you wish.

Now, for the questions related to our project structure.

The webapp project is a pom project with no source that uses the <modules> tag to list each project in the build to form a maven multi-module build. The benefit of a multi-module build is that it allows our developers to change code in any of the projects and run one command line to re-build the war to test.

The webapp project also configures plugins (specifically the maven-resources-plugin, maven-dependency-plugin, gwt-maven-plugin, and maven-assembly-plugin) to copy the src/main/webapp directories from the war-type dependencies into the webapp/war/ directory, copy the dependencies (using Maven dependency management) into the webapp/war/WEB-INF/lib/ directory, execute the GWT compile, and build the WAR file (actually, the war file is only built if not running GWT Development Mode). Because the webapp project uses the <modules> tag to form a multi-module build, it cannot be a war project. Only projects with packaging of type 'pom' can use the Maven <modules> tag.

The only source code we copy from other projects into the webapp/war/ directory is the src/main/webapp/ of war type projects (the web modules, like project2-feature1-module from the example above). I have already explained that we have chosen not to use packaging of type 'war' in those projects because maven-war-plugin war overlays are significantly slower, due to the fact that each fractional war project is made into a war file, installed into your local repo, then, when building your final war, extracted into a directory, then merged into the final war. That process is absurdly slow for the number of web modules that we have.

The projects that have .gwt.xml files in them, which can be any of the projects including the typical jar projects as well as the projects with a src/main/webapp directory (the web modules, like project2-feature1-module from the example above), have a JAR built and installed in the typical fashion, which includes .class files, and the files from src/main/resources. Additionally, we build and install a JAR with a classifier of "gwt" that has the Java source code (not the Java bytecode) and any other resource files that are in src/main/java and src/main/resources. We put the .gwt.xml files and the GWT public folder in src/main/java.

There are reasons behind all of this.

The JAR with a classifier of "gwt" is very similar to a "-sources.jar" built by Maven using the maven-source-plugin. The reason we don't just use the sources JAR is because you can't process the files before they go into the sources JAR, which sometimes we want to do. The sources JAR is just that, the source. All "gwt" JARs are excluded from the WEB-INF/lib directory of the final war to avoid having duplication with the static files from the GWT public folder that GWT compile places in the root of the war file, and to avoid having Java source code in the final war (makes the war file smaller). We put the .gwt.xml files and the GWT public folder in src/main/java so they get included in the "gwt" classifier JAR where they are needed, but not in the JAR with no classifier where they are not needed and would only contribute to bloat of the final war file.

If a GWT module only has code that is used on the client, meaning all of the code will be compiled to JavaScript and placed in the root of the war, then we only reference the "gwt" classifier JAR in our <dependencies>. If it has server-side code also, then we reference both the "gwt" classifier JAR and the JAR with no classifier in our <dependencies>, but the "gwt" classifier JAR is excluded from the WEB-INF/lib of the final war, therefore only the .class files end up in the WEB-INF/lib of the final war, thereby avoiding war file bloat.

Using project1 from above as an example, another alternative would be to give the project1/webapp/pom.xml packaging of type 'war', and move the <modules> tag into the project1/pom.xml. This would mean you would do your multi-module build from the project1/ directory instead of the project1/webapp/ directory. However, there is a problem with this due to the capabilities of the maven-war-plugin. As I just explained, I want to exclude some JARs from the WEB-INF/lib directory of the final war to avoid war file bloat and avoid Java source code in my war (additionally I avoid any classpath trouble in my servlet container). The maven-war-plugin allows you to configure excludes from the final .war file, but not from the exploded war (i.e., the webapp/war/ directory). For us, this presents a problem.

To make development as fast as possible and as close as possible to production environment, we use GWT 2.0 Development Mode with the -noserver option. Typically, to use the -noserver option, you have to first run a GWT compile, then copy files generated by GWT, and your server-side code, over to your servlet container. That means you have two steps before you can test, and the first must execute a GWT compile, which is slow. We run Tomcat as our deployment servlet container, and to avoid this slow, two-step process for development, we simply copy a context.xml file over to Tomcat with a docBase that points back to the webapp/war/ directory, which is the same directory that GWT Development Mode uses.

In the end, with our current setup, we have a large multi-module build, where all you have to do is change to the webapp/ directory, and execute one Maven command to build the project without a GWT compile, deploy the context.xml to Tomcat, and run GWT Development Mode with all projects in the classpath. Meaning you can change UI code in any one of the multiple projects and simply refresh your browser to see the changes. Or, you can execute one Maven command from the webapp/ directory to build the final war file with a GWT compile.

Show
Richard Allen added a comment - - edited First, understand that we are already using a customized gwt-maven-plugin to work around this issue, an issue related to a comment I made on MGWT-75, and to put the source for the projects in the reactor (i.e., the listed <module> s) on the classpath for GWT 2.0 Development Mode without having to list the directories using build-helper-maven-plugin (i.e., less configuration, easier to maintain). Therefore, if you are set against allowing GWT compile to be used with pom projects, so be it, it's not slowing us down. As an effort to contribute back to the community, I commented on this issue to help you and others that might use your plugin. However, I find it odd that you would rather restrict the use of your plugin to specific use cases then simply adjust your fix to make it an option – chosen by default if you wish. Now, for the questions related to our project structure. The webapp project is a pom project with no source that uses the <modules> tag to list each project in the build to form a maven multi-module build. The benefit of a multi-module build is that it allows our developers to change code in any of the projects and run one command line to re-build the war to test. The webapp project also configures plugins (specifically the maven-resources-plugin, maven-dependency-plugin, gwt-maven-plugin, and maven-assembly-plugin) to copy the src/main/webapp directories from the war-type dependencies into the webapp/war/ directory, copy the dependencies (using Maven dependency management) into the webapp/war/WEB-INF/lib/ directory, execute the GWT compile, and build the WAR file (actually, the war file is only built if not running GWT Development Mode). Because the webapp project uses the <modules> tag to form a multi-module build, it cannot be a war project. Only projects with packaging of type 'pom' can use the Maven <modules> tag. The only source code we copy from other projects into the webapp/war/ directory is the src/main/webapp/ of war type projects (the web modules, like project2-feature1-module from the example above). I have already explained that we have chosen not to use packaging of type 'war' in those projects because maven-war-plugin war overlays are significantly slower, due to the fact that each fractional war project is made into a war file, installed into your local repo, then, when building your final war, extracted into a directory, then merged into the final war. That process is absurdly slow for the number of web modules that we have. The projects that have .gwt.xml files in them, which can be any of the projects including the typical jar projects as well as the projects with a src/main/webapp directory (the web modules, like project2-feature1-module from the example above), have a JAR built and installed in the typical fashion, which includes .class files, and the files from src/main/resources. Additionally, we build and install a JAR with a classifier of "gwt" that has the Java source code (not the Java bytecode) and any other resource files that are in src/main/java and src/main/resources. We put the .gwt.xml files and the GWT public folder in src/main/java. There are reasons behind all of this. The JAR with a classifier of "gwt" is very similar to a "-sources.jar" built by Maven using the maven-source-plugin. The reason we don't just use the sources JAR is because you can't process the files before they go into the sources JAR, which sometimes we want to do. The sources JAR is just that, the source. All "gwt" JARs are excluded from the WEB-INF/lib directory of the final war to avoid having duplication with the static files from the GWT public folder that GWT compile places in the root of the war file, and to avoid having Java source code in the final war (makes the war file smaller). We put the .gwt.xml files and the GWT public folder in src/main/java so they get included in the "gwt" classifier JAR where they are needed, but not in the JAR with no classifier where they are not needed and would only contribute to bloat of the final war file. If a GWT module only has code that is used on the client, meaning all of the code will be compiled to JavaScript and placed in the root of the war, then we only reference the "gwt" classifier JAR in our <dependencies>. If it has server-side code also, then we reference both the "gwt" classifier JAR and the JAR with no classifier in our <dependencies>, but the "gwt" classifier JAR is excluded from the WEB-INF/lib of the final war, therefore only the .class files end up in the WEB-INF/lib of the final war, thereby avoiding war file bloat. Using project1 from above as an example, another alternative would be to give the project1/webapp/pom.xml packaging of type 'war', and move the <modules> tag into the project1/pom.xml. This would mean you would do your multi-module build from the project1/ directory instead of the project1/webapp/ directory. However, there is a problem with this due to the capabilities of the maven-war-plugin. As I just explained, I want to exclude some JARs from the WEB-INF/lib directory of the final war to avoid war file bloat and avoid Java source code in my war (additionally I avoid any classpath trouble in my servlet container). The maven-war-plugin allows you to configure excludes from the final .war file, but not from the exploded war (i.e., the webapp/war/ directory). For us, this presents a problem. To make development as fast as possible and as close as possible to production environment, we use GWT 2.0 Development Mode with the -noserver option. Typically, to use the -noserver option, you have to first run a GWT compile, then copy files generated by GWT, and your server-side code, over to your servlet container. That means you have two steps before you can test, and the first must execute a GWT compile, which is slow. We run Tomcat as our deployment servlet container, and to avoid this slow, two-step process for development, we simply copy a context.xml file over to Tomcat with a docBase that points back to the webapp/war/ directory, which is the same directory that GWT Development Mode uses. In the end, with our current setup, we have a large multi-module build, where all you have to do is change to the webapp/ directory, and execute one Maven command to build the project without a GWT compile, deploy the context.xml to Tomcat, and run GWT Development Mode with all projects in the classpath. Meaning you can change UI code in any one of the multiple projects and simply refresh your browser to see the changes. Or, you can execute one Maven command from the webapp/ directory to build the final war file with a GWT compile.

People

Vote (0)
Watch (0)

Dates

  • Created:
    Updated:
    Resolved: