Jetty

Allow provided scope dependencies on classpath

Details

  • Type: Improvement Improvement
  • Status: Resolved Resolved
  • Priority: Major Major
  • Resolution: Fixed
  • Affects Version/s: 6.1.5
  • Fix Version/s: 7.5.2
  • Component/s: Maven
  • Labels:
    None
  • Patch Submitted:
    Yes
  • Number of attachments :
    1

Description

There is a parameter which allows "test" scope dependencies to be added to the Jetty classpath. "Provided" scope dependencies are always ignored. This is an annoyance if you wish to exlcude dependencies from the projects WAR but still have them on the classpath when testing with Jetty.

I have attached a patch which adds a parameter <useProvidedClasspath> to allow this. This was made against the current trunk, but tested with Jetty 6.1.5 as the parent POM as I am unable to compile 6.1-SNAPSHOT of Jetty due to the Glassfish CVS being down (which a checkout of seems to be required at some stage).

Activity

Hide
Jesse McConnell added a comment -

you could also just add a profile to your pom.xml that brings in the dependencies you want for when your running jetty

then you would run something like

mvn -PmoreDeps jetty:run

I have used that for being able to test the webapp with different database dependencies or even with different jetty.xml configurations, simply put the jetty plugin the profile with the configuration to change the jetty.xml locations

anyway, see http://maven.apache.org/pom.html#Profiles for more information

Show
Jesse McConnell added a comment - you could also just add a profile to your pom.xml that brings in the dependencies you want for when your running jetty then you would run something like mvn -PmoreDeps jetty:run I have used that for being able to test the webapp with different database dependencies or even with different jetty.xml configurations, simply put the jetty plugin the profile with the configuration to change the jetty.xml locations anyway, see http://maven.apache.org/pom.html#Profiles for more information
Hide
Martin Gilday added a comment -

Thanks Jesse, I had considered this. I already do that for some dependencies, like the mysql driver. However I would rather not duplicate so many dependencies that are already in my POM.

Show
Martin Gilday added a comment - Thanks Jesse, I had considered this. I already do that for some dependencies, like the mysql driver. However I would rather not duplicate so many dependencies that are already in my POM.
Hide
Jan Bartel added a comment -

I'm a bit reluctant to apply this patch, as I can see lots of jira issues being raised which will all be caused by conflicts
between a different version of the jetty jars in the project dependencies than the version of the plugin being used.

I'm still not quite sure why "test" scope for the dependencies instead of "provided" doesn't suit?

cheers
Jan

Show
Jan Bartel added a comment - I'm a bit reluctant to apply this patch, as I can see lots of jira issues being raised which will all be caused by conflicts between a different version of the jetty jars in the project dependencies than the version of the plugin being used. I'm still not quite sure why "test" scope for the dependencies instead of "provided" doesn't suit? cheers Jan
Hide
Martin Gilday added a comment -

Test scope does not suit as dependencies marked as test are not available when compiling src/main/java, whereas with provided they are.
For example say I have commons-logging in my server lib. I use commons-logging in my application code (in src/main/java). If I mark it as test then it will not compile. If I mark it as provided it will. When I package up my project with scope provided then commons-logging.jar does not appear in my WAR. This is what I see as the main purpose of provided sope. I do not see any point in duplicating all my dependencies in a profile when a scope already exists to solve the issue.

I do not see why there would be any conflicts. If they do not provide the attribute it would default to not including provided scope, so would be exactly the same as it is now.

Show
Martin Gilday added a comment - Test scope does not suit as dependencies marked as test are not available when compiling src/main/java, whereas with provided they are. For example say I have commons-logging in my server lib. I use commons-logging in my application code (in src/main/java). If I mark it as test then it will not compile. If I mark it as provided it will. When I package up my project with scope provided then commons-logging.jar does not appear in my WAR. This is what I see as the main purpose of provided sope. I do not see any point in duplicating all my dependencies in a profile when a scope already exists to solve the issue. I do not see why there would be any conflicts. If they do not provide the attribute it would default to not including provided scope, so would be exactly the same as it is now.
Hide
Jan Bartel added a comment -

Martin,

Thanks for the example with commons-logging. I see what you want to achieve now. However, I think the way to do it is with profiles, or by adding the extra dependencies directly onto the jetty plugin. I realize it's a bit of a hassle to duplicate some of the dependency entries in the pom, however the problem with having a switch that would put all of the "provided" scope dependencies onto the classpath is that then a lot of things could be on the classpath twice, and that's never a good idea, especially with the rather complex classloading hiearachy of maven plugins mixed with a webapp classloader hierarchy.

cheers
Jan

Show
Jan Bartel added a comment - Martin, Thanks for the example with commons-logging. I see what you want to achieve now. However, I think the way to do it is with profiles, or by adding the extra dependencies directly onto the jetty plugin. I realize it's a bit of a hassle to duplicate some of the dependency entries in the pom, however the problem with having a switch that would put all of the "provided" scope dependencies onto the classpath is that then a lot of things could be on the classpath twice, and that's never a good idea, especially with the rather complex classloading hiearachy of maven plugins mixed with a webapp classloader hierarchy. cheers Jan
Hide
Jan Bartel added a comment -

To all those people who voted for this issue and are watching, can I have your comments about the profile solution? I'd still prefer not to allow provided deps for the reasons I gave above, but I'm still prepared to be persuaded, so please present your arguments as convincingly as you can and I'll take another look

Jan

Show
Jan Bartel added a comment - To all those people who voted for this issue and are watching, can I have your comments about the profile solution? I'd still prefer not to allow provided deps for the reasons I gave above, but I'm still prepared to be persuaded, so please present your arguments as convincingly as you can and I'll take another look Jan
Hide
David J. M. Karlsen added a comment -

I'd prefer a flag ala "resolveProvided = true|false".

Having to add deps twice is:
-verbose
-confusing for other developers which are not very maven expirienced ( "why does it say "compile" in the jetty profile - and provided in the dependencyManagement section?")

I cannot see the problem with conflicting versions - if there are conflicts they are conflicts regardless of dep. scope.

As for duplicates - just resolve the dependecies and put them in a HashMap - this should filter out any duplicates.

A LinkedHashSet will also preserve order (if test scope whould appear before compile/provided f.ex).

Show
David J. M. Karlsen added a comment - I'd prefer a flag ala "resolveProvided = true|false". Having to add deps twice is: -verbose -confusing for other developers which are not very maven expirienced ( "why does it say "compile" in the jetty profile - and provided in the dependencyManagement section?") I cannot see the problem with conflicting versions - if there are conflicts they are conflicts regardless of dep. scope. As for duplicates - just resolve the dependecies and put them in a HashMap - this should filter out any duplicates. A LinkedHashSet will also preserve order (if test scope whould appear before compile/provided f.ex).
Hide
David Yu added a comment -

The flag would be better. Default to false.

Show
David Yu added a comment - The flag would be better. Default to false.
Hide
David J. M. Karlsen added a comment -

Any progress on this?

Show
David J. M. Karlsen added a comment - Any progress on this?
Hide
Jesse McConnell added a comment -

in my mind provided dependencies are something that the container is providing to your code...and if you are using the jetty maven plugin as your container, for test or whatever, then you are responsible for configuring the container accordingly and should logically add those dependencies directly to your container, which is functionality provided for by maven in the form of adding dependencies to your plugin declaration. This would be very much akin to making sure that the container you are ultimately deploying to has the required jars in it.

there are enough strange classloader issues in the world I hesitate to add one more special case to the mix

are there any compelling arguments other then verbosity and education issues?

Show
Jesse McConnell added a comment - in my mind provided dependencies are something that the container is providing to your code...and if you are using the jetty maven plugin as your container, for test or whatever, then you are responsible for configuring the container accordingly and should logically add those dependencies directly to your container, which is functionality provided for by maven in the form of adding dependencies to your plugin declaration. This would be very much akin to making sure that the container you are ultimately deploying to has the required jars in it. there are enough strange classloader issues in the world I hesitate to add one more special case to the mix are there any compelling arguments other then verbosity and education issues?
Hide
Tim Meighen added a comment -

My use case for this is when trying to work on a WAR that is part of an EAR. In this case, there are two scopes of provided dependencies: those provided in the parent EAR and those provided by the container. While this may be an edge case, I find that it often speeds development to be able to do web tier work in Jetty rather than building the whole EAR and deploying to the container. For those of us still saddled with legacy EJBs, I think this flag would be of great benefit.

Show
Tim Meighen added a comment - My use case for this is when trying to work on a WAR that is part of an EAR. In this case, there are two scopes of provided dependencies: those provided in the parent EAR and those provided by the container. While this may be an edge case, I find that it often speeds development to be able to do web tier work in Jetty rather than building the whole EAR and deploying to the container. For those of us still saddled with legacy EJBs, I think this flag would be of great benefit.
Hide
baleineca added a comment -

A flag with default value of false seems like the best solution as it would not modify current behaviour while providing the possibility of including provided scoped dependencies when needed.

Show
baleineca added a comment - A flag with default value of false seems like the best solution as it would not modify current behaviour while providing the possibility of including provided scoped dependencies when needed.
Hide
Pavel Volkovitskiy added a comment -

also, according maven docs:
provided - .. This scope is only available on the compilation and test classpath, and is not transitive

so, maven put such deps into test classpath, so why jetty-maven-plugin doesn't uses them with useTestClasspath ?

but if you don't want to change current behavior then adding new flag with default to false will work too

Show
Pavel Volkovitskiy added a comment - also, according maven docs: provided - .. This scope is only available on the compilation and test classpath, and is not transitive so, maven put such deps into test classpath, so why jetty-maven-plugin doesn't uses them with useTestClasspath ? but if you don't want to change current behavior then adding new flag with default to false will work too
Hide
Tim Meighen added a comment -

I ran into this again today. I am building an app that ships with embedded jetty and uses slf4j. The bootstrap class that handles startup/shutdown of jetty also uses slf4j, so I want it in the system classpath and not the webapp. I marked slf4j-api as provided and slf4j-simple as test. When the jetty plugin runs the app dies because it can't find slf4j-api. I ended up having to mark slf4j-simple as "provided" (which is wrong) and duplicate the slf4j-api and slf4j-simple declarations in the plugin configuration.

In my mind, using a profile is a sub-optimal solution. I have done it in the past but it means having to pass this knowledge around the dev team which often doesn't happen. People also tend to forget what custom flag they're supposed to use and then they get frustrated and blame Maven.

Show
Tim Meighen added a comment - I ran into this again today. I am building an app that ships with embedded jetty and uses slf4j. The bootstrap class that handles startup/shutdown of jetty also uses slf4j, so I want it in the system classpath and not the webapp. I marked slf4j-api as provided and slf4j-simple as test. When the jetty plugin runs the app dies because it can't find slf4j-api. I ended up having to mark slf4j-simple as "provided" (which is wrong) and duplicate the slf4j-api and slf4j-simple declarations in the plugin configuration. In my mind, using a profile is a sub-optimal solution. I have done it in the past but it means having to pass this knowledge around the dev team which often doesn't happen. People also tend to forget what custom flag they're supposed to use and then they get frustrated and blame Maven.
Hide
jasseri added a comment - - edited

I was also battling this issue, but using profiles solved the problem just fine. I also have an EAR app, and I want to test a webapp that will be included in the ear with Jetty. In my webapp's pom I defined the following profiles:

<profiles>

<profile>
<id>default</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<shared_dependency_scope>provided</shared_dependency_scope>
</properties>
</profile>

<profile>
<id>jetty</id>
<properties>
<shared_dependency_scope>compile</shared_dependency_scope>
</properties>
</profile>

</profiles>

Then I changed the dependency scope for the dependency in question:

<dependency>

<groupId>myapp</groupId>
<artifactId>myapp_shared</artifactId>
<scope>${shared_dependency_scope}</scope>

</dependency>

Now, when I run a typical mvn clean install, the scope will be 'provided' (activeByDefault set to true for profile 'default'). And when I want to test my webapp with Jetty, I run it like this: 'mvn -P jetty jetty:run'. Works like a charm. The problem for me was that I didn't know profiles too well before running into this issue...

Show
jasseri added a comment - - edited I was also battling this issue, but using profiles solved the problem just fine. I also have an EAR app, and I want to test a webapp that will be included in the ear with Jetty. In my webapp's pom I defined the following profiles: <profiles> <profile> <id>default</id> <activation> <activeByDefault>true</activeByDefault> </activation> <properties> <shared_dependency_scope>provided</shared_dependency_scope> </properties> </profile> <profile> <id>jetty</id> <properties> <shared_dependency_scope>compile</shared_dependency_scope> </properties> </profile> </profiles> Then I changed the dependency scope for the dependency in question: <dependency> <groupId>myapp</groupId> <artifactId>myapp_shared</artifactId> <scope>${shared_dependency_scope}</scope> </dependency> Now, when I run a typical mvn clean install, the scope will be 'provided' (activeByDefault set to true for profile 'default'). And when I want to test my webapp with Jetty, I run it like this: 'mvn -P jetty jetty:run'. Works like a charm. The problem for me was that I didn't know profiles too well before running into this issue...
Hide
Steve Ardis added a comment - - edited

Thanks for the "profile" solution (wasn't very aware of this feature) and I'm using it for the time being.

I'm hoping for a more elegant solution than using profiles though, as I'd rather for developers to be able to pull directly out of source control and run without having to know to pass a "-P" argument to Maven. I envision a solution using something like a <includeProvidedScope> (default to false) element in the <configuration> section of the maven-jetty-plugin; i.e

<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<version>...</version>
<configuration>
<jettyEnvXml>${basedir}/jetty-env.xml</jettyEnvXml>
<includeProvidedScope>true</includeProvidedScope>
</configuration>

This way I can provide sensible defaults for my application.

Steve Ardis

Show
Steve Ardis added a comment - - edited Thanks for the "profile" solution (wasn't very aware of this feature) and I'm using it for the time being. I'm hoping for a more elegant solution than using profiles though, as I'd rather for developers to be able to pull directly out of source control and run without having to know to pass a "-P" argument to Maven. I envision a solution using something like a <includeProvidedScope> (default to false) element in the <configuration> section of the maven-jetty-plugin; i.e <groupId>org.mortbay.jetty</groupId> <artifactId>maven-jetty-plugin</artifactId> <version>...</version> <configuration> <jettyEnvXml>${basedir}/jetty-env.xml</jettyEnvXml> <includeProvidedScope>true</includeProvidedScope> </configuration> This way I can provide sensible defaults for my application. Steve Ardis
Hide
Jan Bartel added a comment -

Ok, I have added a new <configuration> parameter <useProvided>. When true, it will add the dependencies with <scope>provided</scope> onto the plugin's classpath (NOT the webapp's classpath, which is different).

I have tried to eliminate jars that are duplicates between the existing plugin classpath and the provided scope dependencies, however it is still possible to get duplicate classes onto the runtime classpath if the provided scope dependency has a different name. So, please use this flag very carefully. And if you're using it, and the classpath gets all screwed up, please consider "I told you so" before raising a jira for it

Jan

Show
Jan Bartel added a comment - Ok, I have added a new <configuration> parameter <useProvided>. When true, it will add the dependencies with <scope>provided</scope> onto the plugin's classpath (NOT the webapp's classpath, which is different). I have tried to eliminate jars that are duplicates between the existing plugin classpath and the provided scope dependencies, however it is still possible to get duplicate classes onto the runtime classpath if the provided scope dependency has a different name. So, please use this flag very carefully. And if you're using it, and the classpath gets all screwed up, please consider "I told you so" before raising a jira for it Jan

People

Vote (17)
Watch (18)

Dates

  • Created:
    Updated:
    Resolved: