Skip to content

Commit d614bbb

Browse files
committed
Fix log initialization timing
* Support the lazy initialization log * Move the log configuration timing for xml config Fixes mybatisgh-1272
1 parent d5f024c commit d614bbb

File tree

12 files changed

+358
-27
lines changed

12 files changed

+358
-27
lines changed

src/main/java/org/apache/ibatis/builder/xml/XMLConfigBuilder.java

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2009-2017 the original author or authors.
2+
* Copyright 2009-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -105,6 +105,7 @@ private void parseConfiguration(XNode root) {
105105
//issue #117 read properties first
106106
propertiesElement(root.evalNode("properties"));
107107
Properties settings = settingsAsProperties(root.evalNode("settings"));
108+
setLogImpl(settings);
108109
loadCustomVfs(settings);
109110
typeAliasesElement(root.evalNode("typeAliases"));
110111
pluginElement(root.evalNode("plugins"));
@@ -151,6 +152,11 @@ private void loadCustomVfs(Properties props) throws ClassNotFoundException {
151152
}
152153
}
153154

155+
private void setLogImpl(Properties props) {
156+
Class<? extends Log> logImpl = resolveClass(props.getProperty("logImpl"));
157+
configuration.setLogImpl(logImpl);
158+
}
159+
154160
private void typeAliasesElement(XNode parent) {
155161
if (parent != null) {
156162
for (XNode child : parent.getChildren()) {
@@ -262,9 +268,6 @@ private void settingsElement(Properties props) throws Exception {
262268
configuration.setUseActualParamName(booleanValueOf(props.getProperty("useActualParamName"), true));
263269
configuration.setReturnInstanceForEmptyRow(booleanValueOf(props.getProperty("returnInstanceForEmptyRow"), false));
264270
configuration.setLogPrefix(props.getProperty("logPrefix"));
265-
@SuppressWarnings("unchecked")
266-
Class<? extends Log> logImpl = (Class<? extends Log>)resolveClass(props.getProperty("logImpl"));
267-
configuration.setLogImpl(logImpl);
268271
configuration.setConfigurationFactory(resolveClass(props.getProperty("configurationFactory")));
269272
}
270273

src/main/java/org/apache/ibatis/datasource/pooled/PooledDataSource.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2009-2017 the original author or authors.
2+
* Copyright 2009-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -39,7 +39,7 @@
3939
*/
4040
public class PooledDataSource implements DataSource {
4141

42-
private static final Log log = LogFactory.getLog(PooledDataSource.class);
42+
private static final Log log = LogFactory.getLazyInitializationLog(PooledDataSource.class);
4343

4444
private final PoolState state = new PoolState(this);
4545

src/main/java/org/apache/ibatis/executor/loader/javassist/JavassistProxyFactory.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2009-2017 the original author or authors.
2+
* Copyright 2009-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -44,7 +44,7 @@
4444
*/
4545
public class JavassistProxyFactory implements org.apache.ibatis.executor.loader.ProxyFactory {
4646

47-
private static final Log log = LogFactory.getLog(JavassistProxyFactory.class);
47+
private static final Log log = LogFactory.getLazyInitializationLog(JavassistProxyFactory.class);
4848
private static final String FINALIZE_METHOD = "finalize";
4949
private static final String WRITE_REPLACE_METHOD = "writeReplace";
5050

src/main/java/org/apache/ibatis/logging/LogFactory.java

+29-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2009-2016 the original author or authors.
2+
* Copyright 2009-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -15,11 +15,15 @@
1515
*/
1616
package org.apache.ibatis.logging;
1717

18+
import org.apache.ibatis.util.LazyReference;
19+
1820
import java.lang.reflect.Constructor;
21+
import java.lang.reflect.Proxy;
1922

2023
/**
2124
* @author Clinton Begin
2225
* @author Eduardo Macarron
26+
* @author Kazuki Shimizu
2327
*/
2428
public final class LogFactory {
2529

@@ -85,6 +89,30 @@ public static Log getLog(String logger) {
8589
}
8690
}
8791

92+
/**
93+
* Returns a log that lazy initialization.
94+
*
95+
* @param aClass a logger class
96+
* @return a log that lazy initialization(proxied log object)
97+
* @since 3.5.0
98+
*/
99+
public static Log getLazyInitializationLog(Class<?> aClass) {
100+
return getLazyInitializationLog(aClass.getName());
101+
}
102+
103+
/**
104+
* Returns a log that lazy initialization.
105+
*
106+
* @param logger a logger name
107+
* @return a log that lazy initialization(proxied log object)
108+
* @since 3.5.0
109+
*/
110+
public static Log getLazyInitializationLog(String logger) {
111+
LazyReference<Log> logReference = LazyReference.of(() -> getLog(logger));
112+
return (Log) Proxy.newProxyInstance(Log.class.getClassLoader(), new Class<?>[]{Log.class},
113+
(proxy, method, args) -> method.invoke(logReference.get(), args));
114+
}
115+
88116
public static synchronized void useCustomLogging(Class<? extends Log> clazz) {
89117
setImplementation(clazz);
90118
}

src/main/java/org/apache/ibatis/session/AutoMappingUnknownColumnBehavior.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2009-2016 the original author or authors.
2+
* Copyright 2009-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -62,7 +62,7 @@ public void doAction(MappedStatement mappedStatement, String columnName, String
6262
/**
6363
* Logger
6464
*/
65-
private static final Log log = LogFactory.getLog(AutoMappingUnknownColumnBehavior.class);
65+
private static final Log log = LogFactory.getLazyInitializationLog(AutoMappingUnknownColumnBehavior.class);
6666

6767
/**
6868
* Perform the action when detects an unknown column (or unknown property type) of automatic mapping target.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/**
2+
* Copyright 2009-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.apache.ibatis.util;
17+
18+
import java.util.function.Supplier;
19+
20+
/**
21+
* A reference to delay the creation of an object using a {@link Supplier}.
22+
* <p>
23+
* Note, that no concurrency control is applied during the lookup of {@link #get()} or {@link #getNullable()},
24+
* which means in concurrent access scenarios, the provided {@link Supplier} can be called multiple times.
25+
*
26+
* @param <T> object type
27+
* @author Kazuki Shimizu
28+
* @since 3.5.0
29+
*/
30+
public class LazyReference<T> {
31+
32+
private final Supplier<? extends T> supplier;
33+
private T object = null;
34+
private boolean resolved = false;
35+
36+
private LazyReference(Supplier<? extends T> supplier) {
37+
this.supplier = supplier;
38+
}
39+
40+
/**
41+
* Creates a new {@link LazyReference} to produce an object lazily.
42+
*
43+
* @param <T> the type of which to produce an object of eventually.
44+
* @param supplier the {@link Supplier} to create the object lazily.
45+
* @return a new {@link LazyReference}
46+
* @throws IllegalArgumentException If specified supplier is {@literal null}
47+
*/
48+
public static <T> LazyReference<T> of(Supplier<? extends T> supplier) {
49+
if (supplier == null) {
50+
throw new IllegalArgumentException("'supplier' must be specified.");
51+
}
52+
return new LazyReference<>(supplier);
53+
}
54+
55+
/**
56+
* Returns the object created by the specified {@link Supplier}.
57+
* lookups.
58+
*
59+
* @return the object created by the specified {@link Supplier}
60+
* @throws IllegalStateException If the object created by the configured {@link Supplier} is {@literal null}
61+
*/
62+
public T get() {
63+
T object = getNullable();
64+
if (object == null) {
65+
throw new IllegalStateException("Expected lazy evaluation to yield a non-null object but got null.");
66+
}
67+
return object;
68+
}
69+
70+
/**
71+
* Returns the object created by the specified {@link Supplier}.
72+
*
73+
* @return the object created by the specified {@link Supplier}
74+
*/
75+
public T getNullable() {
76+
T resolvedObject = this.object;
77+
if (this.resolved) {
78+
return resolvedObject;
79+
}
80+
T creationObject = supplier.get();
81+
this.object = creationObject;
82+
this.resolved = true;
83+
return creationObject;
84+
}
85+
86+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/**
2+
* Copyright 2009-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
/**
17+
* Utilities.
18+
*/
19+
package org.apache.ibatis.util;

src/test/java/log4j.properties

+1-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#
2-
# Copyright 2009-2016 the original author or authors.
2+
# Copyright 2009-2018 the original author or authors.
33
#
44
# Licensed under the Apache License, Version 2.0 (the "License");
55
# you may not use this file except in compliance with the License.
@@ -20,11 +20,7 @@ log4j.rootLogger=ERROR, stdout
2020
### Uncomment for MyBatis logging
2121
log4j.logger.org.apache.ibatis=ERROR
2222

23-
log4j.logger.org.apache.ibatis.session.AutoMappingUnknownColumnBehavior=WARN, lastEventSavedAppender
24-
2523
### Console output...
2624
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
2725
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
2826
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
29-
30-
log4j.appender.lastEventSavedAppender=org.apache.ibatis.session.AutoMappingUnknownColumnBehaviorTest$LastEventSavedAppender

src/test/java/org/apache/ibatis/logging/LogFactoryTest.java

+46
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@
2828
import org.apache.ibatis.logging.slf4j.Slf4jImpl;
2929
import org.apache.ibatis.logging.stdout.StdOutImpl;
3030
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
31+
import org.apache.ibatis.test.logging.MockitoLogImpl;
3132
import org.junit.Test;
33+
import org.mockito.Mockito;
3234

3335
public class LogFactoryTest {
3436

@@ -106,4 +108,48 @@ private void logSomething(Log log) {
106108
log.error("Error with Exception.", new Exception("Test exception."));
107109
}
108110

111+
@Test
112+
public void shouldLazyInitializationLogByClass() {
113+
Class<? extends Log> currentLogImplClass = LogFactory.getLog(LogFactoryTest.class).getClass();
114+
try {
115+
Log log = LogFactory.getLazyInitializationLog(LogFactoryTest.class);
116+
117+
LogFactory.useCustomLogging(MockitoLogImpl.class);
118+
MockitoLogImpl.reset();
119+
120+
log.warn("log message");
121+
122+
Mockito.verify(MockitoLogImpl.logs.get(LogFactoryTest.class.getName())).warn("log message");
123+
124+
} finally {
125+
try {
126+
LogFactory.useCustomLogging(currentLogImplClass);
127+
} finally {
128+
MockitoLogImpl.reset();
129+
}
130+
}
131+
}
132+
133+
@Test
134+
public void shouldLazyInitializationLogByName() {
135+
String loggerName = LogFactoryTest.class.getName() + ".byName";
136+
Class<? extends Log> currentLogImplClass = LogFactory.getLog(loggerName).getClass();
137+
try {
138+
Log log = LogFactory.getLazyInitializationLog(loggerName);
139+
140+
LogFactory.useCustomLogging(MockitoLogImpl.class);
141+
MockitoLogImpl.reset();
142+
143+
log.warn("log message");
144+
145+
Mockito.verify(MockitoLogImpl.logs.get(loggerName)).warn("log message");
146+
147+
} finally {
148+
try {
149+
LogFactory.useCustomLogging(currentLogImplClass);
150+
} finally {
151+
MockitoLogImpl.reset();
152+
}
153+
}
154+
}
109155
}

src/test/java/org/apache/ibatis/session/AutoMappingUnknownColumnBehaviorTest.java

+18-11
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,21 @@
1919
import org.apache.ibatis.annotations.Select;
2020
import org.apache.ibatis.domain.blog.Author;
2121
import org.apache.ibatis.exceptions.PersistenceException;
22+
import org.apache.ibatis.logging.Log;
23+
import org.apache.ibatis.logging.LogFactory;
2224
import org.apache.ibatis.mapping.Environment;
25+
import org.apache.ibatis.test.logging.MockitoLogImpl;
2326
import org.apache.ibatis.transaction.TransactionFactory;
2427
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
25-
import org.apache.log4j.spi.LoggingEvent;
26-
import org.apache.log4j.varia.NullAppender;
28+
import org.junit.AfterClass;
2729
import org.junit.BeforeClass;
2830
import org.junit.Test;
2931

3032
import javax.sql.DataSource;
3133
import java.util.concurrent.atomic.AtomicInteger;
3234

3335
import static org.assertj.core.api.Assertions.assertThat;
36+
import static org.mockito.Mockito.*;
3437

3538
/**
3639
* Tests for specify the behavior when detects an unknown column (or unknown property type) of automatic mapping target.
@@ -80,24 +83,27 @@ public void setUsername(String username) {
8083
}
8184
}
8285

83-
public static class LastEventSavedAppender extends NullAppender {
84-
private static LoggingEvent event;
85-
86-
public void doAppend(LoggingEvent event) {
87-
LastEventSavedAppender.event = event;
88-
}
89-
}
90-
9186
private static SqlSessionFactory sqlSessionFactory;
87+
private static Class<? extends Log> originalLogImplClass;
9288

9389
@BeforeClass
9490
public static void setup() throws Exception {
91+
originalLogImplClass = LogFactory.getLog(AutoMappingUnknownColumnBehaviorTest.class).getClass();
92+
9593
DataSource dataSource = BaseDataTest.createBlogDataSource();
9694
TransactionFactory transactionFactory = new JdbcTransactionFactory();
9795
Environment environment = new Environment("Production", transactionFactory, dataSource);
9896
Configuration configuration = new Configuration(environment);
9997
configuration.addMapper(Mapper.class);
10098
sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
99+
sqlSessionFactory.getConfiguration().setLogImpl(MockitoLogImpl.class);
100+
101+
MockitoLogImpl.reset();
102+
}
103+
104+
@AfterClass
105+
public static void restore() {
106+
LogFactory.useCustomLogging(originalLogImplClass);
101107
}
102108

103109
@Test
@@ -119,7 +125,8 @@ public void warningCauseByUnknownPropertyType() {
119125
SimpleAuthor author = mapper.selectSimpleAuthor(101);
120126
assertThat(author.getId()).isNull();
121127
assertThat(author.getUsername()).isEqualTo("jim");
122-
assertThat(LastEventSavedAppender.event.getMessage().toString()).isEqualTo("Unknown column is detected on 'org.apache.ibatis.session.AutoMappingUnknownColumnBehaviorTest$Mapper.selectSimpleAuthor' auto-mapping. Mapping parameters are [columnName=ID,propertyName=id,propertyType=java.util.concurrent.atomic.AtomicInteger]");
128+
verify(MockitoLogImpl.logs.get(AutoMappingUnknownColumnBehavior.class.getName()))
129+
.warn("Unknown column is detected on 'org.apache.ibatis.session.AutoMappingUnknownColumnBehaviorTest$Mapper.selectSimpleAuthor' auto-mapping. Mapping parameters are [columnName=ID,propertyName=id,propertyType=java.util.concurrent.atomic.AtomicInteger]");
123130
}
124131
}
125132

0 commit comments

Comments
 (0)