Add log4j maven dependency to war without having it in compile time - maven

Our application uses slf4j, but has dependency to
slf4j api
slf4j over log4j
log4j
The problem is that very often IDE imports classes from log4j and not from slf4j.
Ideally, i want to have only slf4j api as a maven dependency for my application and pack slf4j binding with log4j only at the time i building a war.
I found several solutions so far:
Add libs to WEB-INF/lib folder. This is bad, because i have no maven dependency control and have to store binary in my repo which is not the best thing to do.
Use maven-war plugin with overlays. But as i understand adding dependency to overlay will require to declare dependency (at least as compile)
Is it ok to have only dependency for slf4j api? How to package other dependencies to war without declaring them as project dependencies?
Thanks!

Please simply specify dependency to slf4j-log4j in runtime scope.
So during compile and test time class from runtime scope will not be available.
Also in IDE it shouldn't be visible - I checked it in IntelliJ.
Of course all artifacts with runtime scope will be put in WEB-INF/lib directory.
Example:
...
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
<scope>runtime</scope>
</dependency>
...

Related

Maven: The type cannot be resolved. It is indirectly referenced from required .class files

I changed some existing projects from ant to maven projects.
So far so good.
All projects do have the same groupId.
Theres a project with name "ServerBase" and artifactId "server-base".
Within this project theres an abstract class "BaseService" which defines a logger via:
import org.jboss.logging.Logger;
[...]
protected Logger log = Logger.getLogger(this.getClass());
Theres another project with name "Server" and artifactId "server".
Within this project theres a class ConfigurationDAOImpl extending the BaseService-Class above.
Within ConfigurationDAOImpl the logger log is used for creating some outputs.
Within the "Server"'s POM file I have declared:
<dependency>
<groupId>com.tcom.amadeus</groupId>
<artifactId>server-base</artifactId>
<version>${project.version}</version>
</dependency>
Under BuildPath the dependency is shown very nice under MavenDependencies. I removed the old dirct/natural/ant-dependency from build path before.
If I remove it I am getting very much errors about missing classes etc.
But although I do have this dependency I am getting the followin error in eclipse (under tab markers):
The type org.apache.commons.logging.Log cannot be resolved. It is indirectly referenced from required .class files
Resource: ConfigurationDAPImpl.java
Path: /Server/src/main/...
Location: Line 24
Type: Java Problem
I tried removing the dependency and add it again but without any luck.
Both projects do refer to JAVA 1.8.
Both projects have been build with targets clean an package multiple times.
Both projects have been updated by Righclick or pressing F5.
I am using Eclipse Version: Neon.1a Release (4.6.1)
I am using apache-maven-3.3.9
I am using m2e Plugin.
Any further help would be grateful.
Thanks in advance.
There are two ways to 'solve' this:
1)
explicitly add the required dependency within the server-projects pom-file:
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
</dependency>
2)
change the scop of the required dependency within the server-base-projects pom file from up to now 'provide' to 'compile' or erase the scope tag at all such that the default scope is used by maven (which I guess is 'compile')
old:
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<scope>provided</scope>
</dependency>
new:
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<scope></scope>
</dependency>
or:
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
</dependency>
Some background to this from documentation:
http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Transitive_Dependencies
provided This is much like compile, but indicates you expect the JDK or a container to provide the dependency at runtime. For example,
when building a web application for the Java Enterprise Edition, you
would set the dependency on the Servlet API and related Java EE APIs
to scope provided because the web container provides those classes.
This scope is only available on the compilation and test classpath,
and is not transitive.
Thanks all.
It looks like apache logging library is not brought transitively from your server-base project. Check if in project server under MavenDependencies you see commons-logging (apache logging) jar. If not, then add this as your maven dependency in server-base project.
Repeat the above for all jars that server-base depends on.

gwt + jetty + spring + log4j ERROR: "DOMConfigurator object is not assignable to a Configurator"

This problem was mentioned in several sources around the web but I was unable to solve it with solutions provided there.
PROBLEM:
The following error is thrown from log4j when issuing mvn gwt:run:
[ERROR] log4j:ERROR A "org.apache.log4j.xml.DOMConfigurator" object is not assignable to a "org.apache.log4j.spi.Configurator" variable.
[ERROR] log4j:ERROR The class "org.apache.log4j.spi.Configurator" was loaded by
[ERROR] log4j:ERROR [sun.misc.Launcher$AppClassLoader#23137792] whereas object of type
[ERROR] log4j:ERROR "org.apache.log4j.xml.DOMConfigurator" was loaded by [WebAppClassLoader=Demo#3d1665ac].
[ERROR] log4j:ERROR Could not instantiate configurator [org.apache.log4j.xml.DOMConfigurator].
DESCRIPTION of my project:
I use default jetty server provided with gwt and run it on exploded war.
<gwt.version>2.6.1</gwt.version>
<spring.version>3.2.6.RELEASE</spring.version>
<log4j.version>1.2.17</log4j.version>
<slf4j.version>1.7.5</slf4j.version>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Normally this jar would be listed in dependencies but in my case causes log4j ERROR. -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${slf4j.version}</version>
<scope>runtime</scope>
</dependency>
What's more, I exclude commons-logging from spring and other projects that depend on it.
(not satisfying) SOLUTION:
Logging works fine only when log4j, slf4j-api, slf4j-log4j12 and jcl-over-slf4j jars are put in my WEB-INF/lib directory but only when jcl-over-slf4 is not in the project's classpath (i.e. I comment out the last mentioned dependency).
When jcl-overl-slf4j is included in maven dependencies (see above) it is not only added to target's lib directory but also included in project's classpath. It causes the error. This jar is necessary to be put in lib but the error disappears only when it is not included in the classpath. maven-dependency-plugin is used to work this problem around by copying it into lib directory and skipping maven dependency.
This solution is obviously just a workaround as all four jars - log4j, slf4j-api, slf4j-log4j12, jcl-over-slf4j - are mentioned in many standard examples of gwt and spring projects.
Could you explain why is it behaving that way and how could I solve this with normal inclusion of jcl-over-slf4j in maven dependencies?
Jetty treats org.apache.commons.logging as a system class, i.e. it loads it from the system class loader (i.e. the classpath) in priority over the webapp's WEB-INF/lib. In your case, org.apache.commons.logging is provided by jcl-over-slf4j. So, code in your webapp calls Commons Logging which is then loaded from the system class loader, and it probably initializes SLF4J using the class's class loader (as opposed to the current thread class loader), which thus uses code from slf4j-log4j12 and log4j from the system class loader. Later on, code in the webapp calls into Log4j (possibly through SLF4J) to initialize the logging configuration, and it then uses the JARs from the webapp's WEB-INF/lib (as expected). When it comes to put everything together, then comes the issue, with classes loaded from different class loaders.
Now to solve the issue: it's not straightforward.
Simply put, classloading in DevMode is a mess (see https://docs.google.com/document/d/1bWfafaPA0m0Z1Swodnx7m3QTv31OdqFkE7aeadN_2BU/edit?usp=sharing where I tried to document it).
To solve your issue, you'd have to either use your own ServletContainerLauncher in DevMode with your own classloading rules, or more simply run your webapp in another servlet container (e.g. mvn jetty:run or mvn tomcat7:run, or whatever). Then you'd run DevMode in -noserver mode.
It's a slightly more complex setup, but it has the big advantage of being exactly the one you'll need for SuperDevMode; and SuperDevMode will replace DevMode this year (DevMode is dead already in Firefox, and in Chrome on Linux –basically, it's dead on Linux–, and support will be removed from Chrome on other platforms later this year, leaving only one working platform: Internet Explorer on Windows).

Maven/Spring multi module project logging

I am trying to convert a huge maven/spring webapp to a multi module project.
Logging is implemented with this method (http://docs.spring.io/spring/docs/4.0.2.RELEASE/spring-framework-reference/htmlsingle/#overview-logging-slf4j) in the huge project. What is the correct way to do this in a maven multi module project? Is it necessary to define this in every pom.xml or only in my main pom.xml.
My main pom.xml defines this dependency:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>4.0.2.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
Is it possibly to exclude commons-logging on this dependency?
Update:
The project structure:
Parent Project:
Project A: jar
Project B: jar
Project C: war
Project D: war
All projects using parts of the Spring framework. I am using SLF4J for logging. What is the correct way for including SLF4J in this project setup with maven?
It should only be necessary to exclude commons-logging from "spring-core", but some third-party libraries also include it, so that isn't always enough. You could try using Spring Boot starters to build up your Spring dependencies (even if you aren't using other Boot features), since the default logging system is logback and commons-logging has been carefully excluded.

Spring Jar dependency Presedence

I have one Spring application(CustomerPort). In this I am using one open source jar(commons-lang.2.4). And my CustomerPort using other module, as jar, which using different version "commons-lang.2.2".
Since the other module using commons-lang.2.2, my application also refereeing modules opensource jar instead of commons-lang.2.4.
Could you plz let me how to exclude commons-lang.2.2 in Pom.xml file
use the <scope> tag to correct the scope of these transitive dependencies. Read this for more info on maven dependency scopes
In the pom.xml for CustomerPort, where you specify the dependency on the other jar module, you can specify an exclusion for commons-lang. This will prevent Maven from bringing in the commons-lang transitive dependency from the other jar.
<dependency>
<groupId>otherModuleGroupId</groupId>
<artifactId>otherModuleArtifactId</artifactId>
<version>otherModuleVersion</version>
<exclusions>
<exclusion>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
</exclusion>
</exclusions>
</dependency>
Verify that its doing the right thing by running mvn dependency:tree in CustomerPort.
More info on excluding transitive dependencies here

Is there a maven JBOSS dependency that includes all JBOSS runtime jars?

I have a maven application that will be deployed to JBOSS 5.1 as a war. I want to know how to get it so that Maven can use the JBOSS 5.1 jars (i.e. all the jars in the common/lib folder and any other resources available to JBOSS at runtime) at compile time but not bundle them into the war file.
I thought I could just include some kind of JBOSS dependency with provided scope to do this however I can't find such a dependency. I have done a good bit of searching and can't really find such a dependency. There are a lot of references to pointing to a central JBOSS repository and pulling dependencies from there. I thought there would be just one global dependency that would include all JBOSS runtime jars. Os there such a thing?
If you need more than the standard Java EE API like JBoss packages or resolve some compatibility problems, you can use this dependency :
For JBoss / Java EE 7 Specification APIs
<dependency>
<groupId>org.jboss.spec</groupId>
<artifactId>jboss-javaee-7.0</artifactId>
<version>1.0.1.Final</version>
<type>pom</type>
<scope>provided</scope>
</dependency>
For JBoss / Java EE 6 Specification APIs
<dependency>
<groupId>org.jboss.spec</groupId>
<artifactId>jboss-javaee-6.0</artifactId>
<version>3.0.2.Final</version>
<type>pom</type>
<scope>provided</scope>
</dependency>
For JBoss WildFly 8.2.0.Final complete runtime dependencies
<dependency>
<groupId>org.wildfly</groupId>
<artifactId>wildfly-parent</artifactId>
<version>8.2.0.Final</version>
<type>pom</type>
<scope>provided</scope>
</dependency>
Now, you can also use those POM files to extract the specific dependencies you need.
This could be useful in remote debug time to let your IDE resolve automatically the server dependencies jars and sources currently loaded, or appearing in stacktraces ... in development mode.
In a production MAVEN build, you probably just need this kind of configuration (depending on your JBoss version) :
http://www.mastertheboss.com/jboss-server/wildfly-8/maven-configuration-for-java-ee-7-projects-on-wildfly
Considering JBoss is an EE container, adding the JavaEE dependency should be enough.
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>6.0</version>
<scope>provided</scope>
</dependency>
Scope provided ensures that JBoss's own libraries are used once the application is deployed to the server.

Resources