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
我正在 运行 一些单元测试,我要使用 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 theSAXParserFactory
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