{"action":"created","issue":{"url":"https://api.github.com/repos/flyway/flyway/issues/1922","repository_url":"https://api.github.com/repos/flyway/flyway","labels_url":"https://api.github.com/repos/flyway/flyway/issues/1922/labels{/name}","comments_url":"https://api.github.com/repos/flyway/flyway/issues/1922/comments","events_url":"https://api.github.com/repos/flyway/flyway/issues/1922/events","html_url":"https://github.com/flyway/flyway/issues/1922","id":296169798,"number":1922,"title":"LogFactory should not use TCCL when locating logging implementation: can cause NoClassDefFoundError: org/slf4j/LoggerFactory","user":{"login":"javabrett","id":1103477,"avatar_url":"https://avatars1.githubusercontent.com/u/1103477?v=4","gravatar_id":"","url":"https://api.github.com/users/javabrett","html_url":"https://github.com/javabrett","followers_url":"https://api.github.com/users/javabrett/followers","following_url":"https://api.github.com/users/javabrett/following{/other_user}","gists_url":"https://api.github.com/users/javabrett/gists{/gist_id}","starred_url":"https://api.github.com/users/javabrett/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/javabrett/subscriptions","organizations_url":"https://api.github.com/users/javabrett/orgs","repos_url":"https://api.github.com/users/javabrett/repos","events_url":"https://api.github.com/users/javabrett/events{/privacy}","received_events_url":"https://api.github.com/users/javabrett/received_events","type":"User","site_admin":false},"labels":[{"id":44944246,"url":"https://api.github.com/repos/flyway/flyway/labels/m:%20Core","name":"m: Core","color":"6634a3","default":false},{"id":164837567,"url":"https://api.github.com/repos/flyway/flyway/labels/s:%20waiting%20for%20feedback","name":"s: waiting for feedback","color":"fbca04","default":false},{"id":22191326,"url":"https://api.github.com/repos/flyway/flyway/labels/t:%20bug","name":"t: bug","color":"fc2929","default":false}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":{"url":"https://api.github.com/repos/flyway/flyway/milestones/17","html_url":"https://github.com/flyway/flyway/milestone/17","labels_url":"https://api.github.com/repos/flyway/flyway/milestones/17/labels","id":2767884,"number":17,"title":"Flyway 5.1.0","description":"","creator":{"login":"axelfontaine","id":684824,"avatar_url":"https://avatars2.githubusercontent.com/u/684824?v=4","gravatar_id":"","url":"https://api.github.com/users/axelfontaine","html_url":"https://github.com/axelfontaine","followers_url":"https://api.github.com/users/axelfontaine/followers","following_url":"https://api.github.com/users/axelfontaine/following{/other_user}","gists_url":"https://api.github.com/users/axelfontaine/gists{/gist_id}","starred_url":"https://api.github.com/users/axelfontaine/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/axelfontaine/subscriptions","organizations_url":"https://api.github.com/users/axelfontaine/orgs","repos_url":"https://api.github.com/users/axelfontaine/repos","events_url":"https://api.github.com/users/axelfontaine/events{/privacy}","received_events_url":"https://api.github.com/users/axelfontaine/received_events","type":"User","site_admin":false},"open_issues":86,"closed_issues":3,"state":"open","created_at":"2017-09-15T09:43:57Z","updated_at":"2018-02-11T11:27:16Z","due_on":"2018-03-06T08:00:00Z","closed_at":null},"comments":4,"created_at":"2018-02-11T07:49:25Z","updated_at":"2018-02-13T10:38:52Z","closed_at":null,"author_association":"NONE","body":"###### What version of Flyway are you using?\r\n\r\n5.0.7.\r\n\r\n###### Which client are you using? (Command-line, Java API, Maven plugin, Gradle plugin, SBT plugin, ANT tasks)\r\n\r\nJava API.\r\n\r\n###### What database are you using (type & version)?\r\n\r\nMySQL, Oracle DB, multiple versions.\r\n\r\n###### What operating system are you using?\r\n\r\nLinux, OS/X\r\n\r\n# TL;DR\r\n\r\n`org.flywaydb.core.api.logging.LogFactory` uses the Thread Context Class Loader (TCCL) when _discovering_ which logging APIs/backends are available for its own logging.  It should not do this as the TCCL is not subsequently used to _load_ the logging-API, which is loaded as-normal by the classloader of `LogFactory` itself, which is not necessarily the same classloader with the same class-visibility.  This can lead to a `NoClassDefFoundError: org/slf4j/LoggerFactory`, especially in certain JavaEE packaging scenarios.\r\n\r\n# Problem demonstration\r\n\r\nThis problem was noticed in a real application-scenario, but can be simplified and reproduced as-follows:\r\n\r\n* Package a Java EE application as an EAR.  For simplicity it contains some common libraries (including Flyway) and a single web-application (WAR).\r\n* The web-application uses Flyway, either directly or wrapped in some other logic.  The important factor is that it is desired to deploy Flyway to some parent-classloader - either the EAR's libs, or some application-server/domain common-classloader.\r\n* The WAR file has SLF4J packaged for its own logging.\r\n* SLF4J is not deployed in the parent classloader where Flyway is deployed.\r\n\r\nWhen `Flyway` is first classloaded, it initializes its own logging, and uses the TCCL classloader for detection of the available logging APIs (SLF4J, Apache Commons Logging), but when loading the API-wrapper e.g. `Slf4jLogCreator`, normal classloading is used, which is _not_ the TCCL.  In the above scenario this will yield:\r\n\r\n```\r\nCaused by: java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory\r\n    at org.flywaydb.core.internal.util.logging.slf4j.Slf4jLogCreator.createLogger(Slf4jLogCreator.java:27)\r\n    at org.flywaydb.core.api.logging.LogFactory.getLog(LogFactory.java:82)\r\n    at org.flywaydb.core.internal.util.ClassUtils.<clinit>(ClassUtils.java:37)\r\n    at org.flywaydb.core.internal.util.FeatureDetector.isSlf4jAvailable(FeatureDetector.java:96)\r\n    at org.flywaydb.core.api.logging.LogFactory.getLog(LogFactory.java:71)\r\n    at org.flywaydb.core.internal.util.FeatureDetector.<clinit>(FeatureDetector.java:25)\r\n    at org.flywaydb.core.api.logging.LogFactory.getLog(LogFactory.java:68)\r\n    at org.flywaydb.core.Flyway.<clinit>(Flyway.java:72)\r\n    at test.flywaydb.ContextListener.contextInitialized(ContextListener.java:26)\r\n```\r\n\r\n# Code\r\n\r\n[`LogFactory`](https://github.com/flyway/flyway/blob/master/flyway-core/src/main/java/org/flywaydb/core/api/logging/LogFactory.java#L68) creates a [`FeatureDetector`](https://github.com/flyway/flyway/blob/master/flyway-core/src/main/java/org/flywaydb/core/internal/util/FeatureDetector.java#L37) passing the TCCL as the classloader to be used in feature-tests.  Later at https://github.com/flyway/flyway/blob/master/flyway-core/src/main/java/org/flywaydb/core/api/logging/LogFactory.java#L72 a `Slf4jLogCreator` is instantiated directly using `LogFactory`'s classloader, which is not necessarily the TCCL, leading to the possibility of a NCDFE.\r\n\r\n# Analysis\r\n\r\nIn a JavaEE application the TCCL will often be set to a leaf classloader e.g a `WebappClassLoader` with visibility of parent classloaders, and perhaps other libraries like SLF4J.  It is reasonable that Flyway might be loaded by some parent/shared classloader.  It should not use the TCCL classloaders when testing what classes it can load for itself e.g. for the purposes of obtaining a logging-API, since the TCCL may be a child classloader with classes not-visible to Flyway.  This is the case in a JavaEE deployment where FLyway is loaded by a classloader which is a parent to the TCCL e.g. an `EarLibClassLoader `."},"comment":{"url":"https://api.github.com/repos/flyway/flyway/issues/comments/365223558","html_url":"https://github.com/flyway/flyway/issues/1922#issuecomment-365223558","issue_url":"https://api.github.com/repos/flyway/flyway/issues/1922","id":365223558,"user":{"login":"axelfontaine","id":684824,"avatar_url":"https://avatars2.githubusercontent.com/u/684824?v=4","gravatar_id":"","url":"https://api.github.com/users/axelfontaine","html_url":"https://github.com/axelfontaine","followers_url":"https://api.github.com/users/axelfontaine/followers","following_url":"https://api.github.com/users/axelfontaine/following{/other_user}","gists_url":"https://api.github.com/users/axelfontaine/gists{/gist_id}","starred_url":"https://api.github.com/users/axelfontaine/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/axelfontaine/subscriptions","organizations_url":"https://api.github.com/users/axelfontaine/orgs","repos_url":"https://api.github.com/users/axelfontaine/repos","events_url":"https://api.github.com/users/axelfontaine/events{/privacy}","received_events_url":"https://api.github.com/users/axelfontaine/received_events","type":"User","site_admin":false},"created_at":"2018-02-13T10:38:52Z","updated_at":"2018-02-13T10:38:52Z","author_association":"CONTRIBUTOR","body":"Not in a hurry. I'm hoping to address this in the coming month to get it out as part of Flyway 5.1. If we miss that window, it'll be 5.2. No biggie."}}
{"actor":{"display_login":"axelfontaine"}}