4

I had a Java 8 project and my configuration file was in resource folder and everything worked fine. Now I switched to Java 9, added requirement for log4j.api, and configuration file cannot be found anymore.

Do I need to add something else in my module-info file for the logger to find it's config?

For now, it's like this

module project.main {
    requires jdk.incubator.httpclient;
    requires jackson.databind;
    requires jackson.core;
    requires jackson.annotations;
    requires log4j.api;
}

The Project structure is as:

structure

The build.gradle file is as:

enter image description here

Naman
  • 27,789
  • 26
  • 218
  • 353
EmberTraveller
  • 355
  • 3
  • 18
  • whats your current directory structure and what was the way you were using to map your resource in java 8? – Naman Sep 10 '17 at 09:08
  • @nullpointer - src/main/java - src/main/resources - src/main/java/package1 - src/main/java/package2 - src/main/java/module-info.java - src/main/resources/log4j2.xml But i'm not sure about the second question, i didn't really do any mapping myself, just added dependency and created config file and that's it. – EmberTraveller Sep 10 '17 at 09:23
  • Could you rather update a screenshot/hierarchy of your project structure in the question itself? Also, how are you importing the log4j module? Please mention the version of the jar/artifact used. – Naman Sep 10 '17 at 09:26
  • 3
    If log4j2.xml (sp?) is found with JDK 8 then it should be found with JDK 9 too. Resources that are in the top-level directory of a module are not encapsulated. If the configuration file were in a different location, say foo/resources/log4j.xml then it would be encapsulated and the module would need to `opens foo.resources` to allow libraries that scan the class path (like log4j) to locate it. – Alan Bateman Sep 10 '17 at 09:28
  • 1
    @nullpointer i thought that comment would save my formatting, added image. importing log4j using gradle, version is 2.9.0 – EmberTraveller Sep 10 '17 at 09:37
  • @EmberTraveller Could you share your build.gradle as well. It works fine for me on maven with 2.9.0 of log4j. – Naman Sep 10 '17 at 12:08
  • @nullpointer added – EmberTraveller Sep 10 '17 at 12:20
  • @EmberTraveller ya apparently you need the `api` dependency as well as suggested in the log4j faqs. Made an answer to what I was able to run on maven and a similar implementation that can be made to gradle. – Naman Sep 10 '17 at 12:28

1 Answers1

3

The log4j~faq suggests using at least log4j-api-2.x and log4j-core-2.x. Preferably add these to your build.gradle file:

compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.9.0'
compile group: 'org.apache.logging.log4j', name: 'log4j-slf4j-impl', version: '2.9.0'
compile group: 'org.apache.logging.log4j', name: 'log4j-1.2-api', version: '2.9.0'

And make sure conflicting dependencies are excluded


In the module-info.java further you shall update(this is what I did in a custom maven project)

requires log4j; // not log4j.api

It should work for you then with the same directory structure as well.


Hint: This is where I started debugging it from. Why do I see a warning about "No appenders found for logger" and "Please configure log4j properly"?

This occurs when the default configuration files log4j.properties and log4j.xml can not be found and the application performs no explicit configuration. log4j uses Thread.getContextClassLoader().getResource() to locate the default configuration files and does not directly check the file system...

Placed a debug point in the ClassLoader#getResource method and just keep an eye of resources looked for by the library.


Also to bring up the point over resources like resources/foo/bar/log4j.properties as stated in the release notes in JDK-8142968

  • JDK internal resources, other than class files, in the standard and JDK modules can no longer be located with the ClassLoader.getResourceXXXAPIs. This may impact code that relies on using these APIs to get at JDK internal properties files or other resources.

and seconded by the java-doc of ClassLoader#getResource as well:

  • Resources in named modules are subject to the encapsulation rules specified by Module.getResourceAsStream. Additionally, and except for the special case where the resource has a name ending with ".class", this method will only find resources in packages of named modules when the package is opened unconditionally (even if the caller of this method is in the same module as the resource).
Naman
  • 27,789
  • 26
  • 218
  • 353
  • 2
    If log4j-api-2.9.0.jar is used as automatic module then the derived name is "log4j.api" and so the `requires` directive in the question looks right. As log4j is pluggable then it needs an implementation, probably the implementation in log4j-core-2.9.0.jar in this case. You should be able to deploy the implementation on the module path or class path, the API will locate it. As regards the configuration file log4j2.xml then will be located in module project.main's top-level directory. It will also be found if it's on the class path. – Alan Bateman Sep 10 '17 at 14:44
  • @Alan The directive I had used was as suggested by intelliJ, though it looked doubtful to me as well if the automatic module would be named so. Trying log4j.api dies not resolve as a module as well. Guess I would have to manually create the module for such case? And related to the resource, my understanding is, that the way to access them changes in terms of encapsulation of internal resources and not the top level directory..please correct me if I am wrong. – Naman Sep 10 '17 at 14:57
  • Thank you a lot for your answer. I created maven project and everything worked, but when i tried to create gradle project with Java 9 to see if it works, I actually got an error "Error:BUG! exception in phase 'class generation' in source unit '_BuildScript_' unsupported Target MODULE" , googled about for a bit and saw that some people had the same problem just recently. So maybe somthing do to with gradle actually. Anyway thank you for sticking wiht this problem for so long! – EmberTraveller Sep 10 '17 at 15:44
  • @EmberTraveller you can raise that as a bug in gradle's tracker. Hope someone would come back with a fix over it. – Naman Sep 10 '17 at 16:14
  • 2
    @nullpointer - log4j ships with a JAR file named log4j-1.2-api-2.9.0.jar that is used for bridging by applications using the old log4j API. It's module name will "log4j" if used as automatic module. On the question on if log4j2.xml is encapsulation then the answer is "no" because it's the top-level directory. The top-level directory is the equivalent to the unnamed package and so is not a member of the module (as a module only contains named packages). – Alan Bateman Sep 10 '17 at 18:43