slf4j - Spring MVC 测试中的 logback NullPointer

slf4j - logback NullPointer in Spring MVC tests

我正在 运行 一些单元测试,我要使用 SLF4J 和 logback。

这里是相关的pom.xml

     <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>4.2.6-RELEASE</version>
    <exclusions>
      <exclusion>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
      </exclusion>
    </exclusions>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.1.7</version>
</dependency>   
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jcl-over-slf4j</artifactId>
    <version>1.7.21</version>
</dependency>

这是日志和堆栈跟踪:

20:29:16,293 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Found resource [logback-test.xml] at [file:/code/web/target/test-classes/logback-test.xml]
20:29:16,387 |-ERROR in ch.qos.logback.core.joran.event.SaxEventRecorder@7a1ebcd8 - Unexpected exception while parsing XML document. java.lang.NullPointerException
at java.lang.NullPointerException
at  at org.xml.sax.helpers.LocatorImpl.<init>(LocatorImpl.java:103)
at  at ch.qos.logback.core.joran.event.SaxEvent.<init>(SaxEvent.java:31)
at  at ch.qos.logback.core.joran.event.StartEvent.<init>(StartEvent.java:27)
at  at ch.qos.logback.core.joran.event.SaxEventRecorder.startElement(SaxEventRecorder.java:106)
at  at org.allcolor.xml.parser.CShaniSaxParser.parseStartTag(CShaniSaxParser.java:1393)
at  at org.allcolor.xml.parser.CXmlParser.parseSTARTTag(CXmlParser.java:1405)
at  at org.allcolor.xml.parser.CXmlParser.parse(CXmlParser.java:682)
at  at org.allcolor.xml.parser.CShaniSaxParser.parse(CShaniSaxParser.java:767)
at  at javax.xml.parsers.SAXParser.parse(SAXParser.java:392)
at  at ch.qos.logback.core.joran.event.SaxEventRecorder.recordEvents(SaxEventRecorder.java:59)
at  at ch.qos.logback.core.joran.GenericConfigurator.doConfigure(GenericConfigurator.java:141)
at  at ch.qos.logback.core.joran.GenericConfigurator.doConfigure(GenericConfigurator.java:103)
at  at ch.qos.logback.core.joran.GenericConfigurator.doConfigure(GenericConfigurator.java:53)
at  at ch.qos.logback.classic.util.ContextInitializer.configureByResource(ContextInitializer.java:75)
at  at ch.qos.logback.classic.util.ContextInitializer.autoConfig(ContextInitializer.java:150)
at  at org.slf4j.impl.StaticLoggerBinder.init(StaticLoggerBinder.java:84)
at  at org.slf4j.impl.StaticLoggerBinder.<clinit>(StaticLoggerBinder.java:55)
at  at org.slf4j.LoggerFactory.bind(LoggerFactory.java:150)
at  at org.slf4j.LoggerFactory.performInitialization(LoggerFactory.java:124)
at  at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:412)
at  at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:357)
at  at org.apache.commons.logging.impl.SLF4JLogFactory.getInstance(SLF4JLogFactory.java:155)
at  at org.apache.commons.logging.impl.SLF4JLogFactory.getInstance(SLF4JLogFactory.java:132)
at  at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:685)
at  at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.<clinit>(SpringJUnit4ClassRunner.java:91)
at  at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at  at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at  at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at  at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
at  at org.junit.internal.builders.AnnotatedBuilder.buildRunner(AnnotatedBuilder.java:104)

和 logback-test.xml:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>.%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg %n
            </Pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>TRACE</level>
        </filter>
    </appender>
    <root>
        <level value="INFO" />
        <appender-ref ref="consoleAppender" />
    </root> 
    <logger name="com.me.ControllerTester" level="debug" additivity="false">
        <appender-ref ref="consoleAppender" />
    </logger>
</configuration>

现在我检查了依赖树,没有任何冲突。我试过弄乱 SAX 解析器版本。

XML 我觉得不错。我一定是有点矛盾...

有什么想法吗?

logback 使用 SAXParserFactory.newInstance(),它有一个查找过程来确定要使用的实现。根据此查找,似乎在您的环境中选择了 org.allcolor.xml.parser.CShaniSaxParser

public static SAXParserFactory newInstance()

Obtain a new instance of a SAXParserFactory. This static method creates a new factory instance This method uses the following ordered lookup procedure to determine the SAXParserFactory implementation class to load:

  • Use the javax.xml.parsers.SAXParserFactory system property.
  • Use the properties file "lib/jaxp.properties" in the JRE directory. This configuration file is in standard java.util.Properties format and contains the fully qualified name of the implementation class with the key being the system property defined above. The jaxp.properties file is read only once by the JAXP implementation and it's values are then cached for future use. If the file does not exist when the first attempt is made to read from it, no further attempts are made to check for its existence. It is not possible to change the value of any property in jaxp.properties after it has been read for the first time.
  • Use the Services API (as detailed in the JAR specification), if available, to determine the classname. The Services API will look for a classname in the file META-INF/services/javax.xml.parsers.SAXParserFactory in jars available to the runtime.
  • Platform default SAXParserFactory instance.

Once an application has obtained a reference to a SAXParserFactory it can use the factory to configure and obtain parser instances.

Tip for Trouble-shooting

Setting the jaxp.debug system property will cause this method to print a lot of debug messages to System.err about what it is doing and where it is looking at.

If you have problems loading DocumentBuilders, try:

java -Djaxp.debug=1 YourProgram ....

尝试通过为单元测试设置 javax.xml.parsers.SAXParserFactory 系统 属性 来切换到标准 SAX 解析器(例如 Apache Xerces):

-Djavax.xml.parsers.SAXParserFactory=org.apache.xerces.jaxp.SAXParserFactoryImpl