• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

future-architect / uroborosql / #767

26 Aug 2024 05:08PM UTC coverage: 90.274% (-0.9%) from 91.21%
#767

push

HidekiSugimoto189
各Logger用のインタフェースを作成し必要なクラスがimplementsするように修正。そのうえでSLF4J 2.xのAPIを利用するように変更(性能改善)

360 of 568 new or added lines in 32 files covered. (63.38%)

9 existing lines in 7 files now uncovered.

8864 of 9819 relevant lines covered (90.27%)

0.9 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

71.81
/src/main/java/jp/co/future/uroborosql/context/ExecutionContextProviderImpl.java
1
/**
2
 * Copyright (c) 2017-present, Future Corporation
3
 *
4
 * This source code is licensed under the MIT license found in the
5
 * LICENSE file in the root directory of this source tree.
6
 */
7
package jp.co.future.uroborosql.context;
8

9
import java.io.IOException;
10
import java.lang.reflect.Modifier;
11
import java.net.JarURLConnection;
12
import java.net.URISyntaxException;
13
import java.net.URL;
14
import java.nio.file.Files;
15
import java.nio.file.Path;
16
import java.nio.file.Paths;
17
import java.sql.ResultSet;
18
import java.time.Clock;
19
import java.util.ArrayList;
20
import java.util.Collection;
21
import java.util.Collections;
22
import java.util.HashMap;
23
import java.util.HashSet;
24
import java.util.List;
25
import java.util.Map;
26
import java.util.Objects;
27
import java.util.Optional;
28
import java.util.Set;
29
import java.util.StringJoiner;
30
import java.util.concurrent.ConcurrentHashMap;
31
import java.util.jar.JarEntry;
32
import java.util.jar.JarFile;
33
import java.util.stream.Collectors;
34

35
import jp.co.future.uroborosql.config.SqlConfig;
36
import jp.co.future.uroborosql.event.AfterInitializeExecutionContextEvent;
37
import jp.co.future.uroborosql.log.ServiceLogger;
38
import jp.co.future.uroborosql.log.SettingLogger;
39
import jp.co.future.uroborosql.parameter.Parameter;
40
import jp.co.future.uroborosql.parameter.mapper.BindParameterMapper;
41
import jp.co.future.uroborosql.parameter.mapper.BindParameterMapperManager;
42
import jp.co.future.uroborosql.utils.CaseFormat;
43
import jp.co.future.uroborosql.utils.ObjectUtils;
44

45
/**
46
 * ExecutionContextプロバイダ実装
47
 *
48
 * @author H.Sugimoto
49
 */
50
public class ExecutionContextProviderImpl implements ExecutionContextProvider, ServiceLogger, SettingLogger {
1✔
51
        /** 定数パラメータプレフィックス */
52
        private String constParamPrefix = "CLS_";
1✔
53

54
        /** 定数クラス名(FQDN) */
55
        private List<String> constantClassNames = new ArrayList<>();
1✔
56
        /** Enum定数パッケージ名 */
57
        private List<String> enumConstantPackageNames = new ArrayList<>();
1✔
58

59
        /** 定数パラメータマップ */
60
        private Map<String, Parameter> constParameterMap = null;
1✔
61

62
        /** SQL設定クラス */
63
        private SqlConfig sqlConfig = null;
1✔
64

65
        /** ResultSetTypeの初期値 */
66
        private int defaultResultSetType = ResultSet.TYPE_FORWARD_ONLY;
1✔
67

68
        /** ResultSetConcurrencyの初期値*/
69
        private int defaultResultSetConcurrency = ResultSet.CONCUR_READ_ONLY;
1✔
70

71
        /** パラメータ変換マネージャ */
72
        private BindParameterMapperManager parameterMapperManager = new BindParameterMapperManager(
1✔
73
                        Clock.systemDefaultZone());
1✔
74

75
        /**
76
         * {@inheritDoc}
77
         *
78
         * @see jp.co.future.uroborosql.context.ExecutionContextProvider#createExecutionContext()
79
         */
80
        @Override
81
        public ExecutionContext createExecutionContext() {
82
                var executionContext = new ExecutionContextImpl();
1✔
83
                executionContext.setSqlConfig(getSqlConfig());
1✔
84
                executionContext.setConstParameterMap(new ConcurrentHashMap<>(getConstParameterMap()));
1✔
85
                executionContext.setParameterMapperManager(
1✔
86
                                new BindParameterMapperManager(parameterMapperManager, getSqlConfig().getClock()));
1✔
87
                executionContext.setResultSetType(defaultResultSetType);
1✔
88
                executionContext.setResultSetConcurrency(defaultResultSetConcurrency);
1✔
89

90
                // ExecutionContext初期化後イベント発行
91
                if (getSqlConfig().getEventListenerHolder().hasAfterInitializeExecutionContextListener()) {
1✔
92
                        var eventObj = new AfterInitializeExecutionContextEvent(executionContext);
1✔
93
                        getSqlConfig().getEventListenerHolder().getAfterInitializeExecutionContextListeners()
1✔
94
                                        .forEach(listener -> listener.accept(eventObj));
1✔
95
                }
96
                return executionContext;
1✔
97
        }
98

99
        /**
100
         * {@inheritDoc}
101
         *
102
         * @see jp.co.future.uroborosql.config.SqlConfigAware#setSqlConfig(jp.co.future.uroborosql.config.SqlConfig)
103
         */
104
        @Override
105
        public void setSqlConfig(final SqlConfig sqlConfig) {
106
                this.sqlConfig = sqlConfig;
1✔
107
        }
1✔
108

109
        /**
110
         * {@inheritDoc}
111
         *
112
         * @see jp.co.future.uroborosql.config.SqlConfigAware#getSqlConfig()
113
         */
114
        @Override
115
        public SqlConfig getSqlConfig() {
116
                return sqlConfig;
1✔
117
        }
118

119
        /**
120
         * {@inheritDoc}
121
         *
122
         * @see jp.co.future.uroborosql.context.ExecutionContextProvider#initialize()
123
         */
124
        @Override
125
        public void initialize() {
126
                parameterMapperManager = new BindParameterMapperManager(parameterMapperManager, getSqlConfig().getClock());
1✔
127

128
                var paramMap = new HashMap<String, Parameter>(buildConstParamMap());
1✔
129
                paramMap.putAll(buildEnumConstParamMap());
1✔
130
                constParameterMap = Collections.unmodifiableMap(paramMap);
1✔
131
        }
1✔
132

133
        /**
134
         * 定数パラメータのMapを生成する
135
         *
136
         * @param paramMap 定数パラメータを保持するMap
137
         * @param targetClass 定数パラメータを生成する定数クラス。クラス内に内部クラスを持つ場合は内部クラスの定数フィールドもパラメータに登録する
138
         */
139
        protected void makeConstParamMap(final Map<String, Parameter> paramMap,
140
                        final Class<?> targetClass) {
141
                try {
142
                        var fieldPrefix = targetClass.isMemberClass() ? CaseFormat.UPPER_SNAKE_CASE
1✔
143
                                        .convert(targetClass.getSimpleName()) + "_" : "";
1✔
144
                        // 指定されたクラス直下の定数フィールドを追加
145
                        var fields = targetClass.getFields();
1✔
146
                        for (var field : fields) {
1✔
147
                                var mod = field.getModifiers();
1✔
148
                                if (Modifier.isFinal(mod) && Modifier.isStatic(mod)) {
1✔
149
                                        var value = field.get(null);
1✔
150
                                        if (parameterMapperManager.canAcceptByStandard(value)) {
1✔
151
                                                var fieldName = getConstParamPrefix() + fieldPrefix + field.getName();
1✔
152
                                                fieldName = fieldName.toUpperCase();
1✔
153
                                                var newValue = new Parameter(fieldName, field.get(null));
1✔
154
                                                var prevValue = paramMap.put(fieldName, newValue);
1✔
155
                                                if (prevValue != null) {
1✔
NEW
156
                                                        SETTING_LOG.atWarn()
×
NEW
157
                                                                        .setMessage("Duplicate constant name. Constant name:{}, old value:{} destroy.")
×
NEW
158
                                                                        .addArgument(fieldName)
×
NEW
159
                                                                        .addArgument(prevValue.getValue())
×
NEW
160
                                                                        .log();
×
161
                                                }
162
                                                SETTING_LOG.atInfo()
1✔
163
                                                                .setMessage("Constant [name:{}, value:{}] added to parameter.")
1✔
164
                                                                .addArgument(fieldName)
1✔
165
                                                                .addArgument(newValue.getValue())
1✔
166
                                                                .log();
1✔
167
                                        }
168
                                }
169
                        }
170

171
                        // 内部クラスを持つ場合
172
                        var memberClasses = targetClass.getDeclaredClasses();
1✔
173
                        for (var memberClass : memberClasses) {
1✔
174
                                var mod = memberClass.getModifiers();
1✔
175
                                if (Modifier.isFinal(mod) && Modifier.isPublic(mod)) {
1✔
176
                                        makeConstParamMap(paramMap, memberClass);
1✔
177
                                }
178
                        }
179
                } catch (IllegalArgumentException | IllegalAccessException | SecurityException ex) {
×
NEW
180
                        LOG.atError()
×
NEW
181
                                        .setMessage(ex.getMessage())
×
NEW
182
                                        .setCause(ex)
×
NEW
183
                                        .log();
×
184
                }
1✔
185
        }
1✔
186

187
        /**
188
         * Enum型の定数パラメータのMapを生成する
189
         *
190
         * @param paramMap 定数パラメータを保持するMap
191
         * @param packageName パッケージ名
192
         * @param targetClass 対象Enumクラス
193
         */
194
        protected void makeEnumConstParamMap(final Map<String, Parameter> paramMap,
195
                        final String packageName,
196
                        final Class<? extends Enum<?>> targetClass) {
197

198
                var fieldPrefix = CaseFormat.UPPER_SNAKE_CASE.convert(targetClass.getName().substring(
1✔
199
                                packageName.length() + 1)) + "_";
1✔
200

201
                var enumValues = targetClass.getEnumConstants();
1✔
202

203
                for (var value : enumValues) {
1✔
204
                        var fieldName = (getConstParamPrefix() + fieldPrefix + value.name().toUpperCase()).toUpperCase();
1✔
205
                        var newValue = new Parameter(fieldName, value);
1✔
206
                        var prevValue = paramMap.put(fieldName, newValue);
1✔
207
                        if (prevValue != null) {
1✔
NEW
208
                                SETTING_LOG.atWarn()
×
NEW
209
                                                .setMessage("Duplicate Enum name. Enum name:{}, old value:{} destroy.")
×
NEW
210
                                                .addArgument(fieldName)
×
NEW
211
                                                .addArgument(prevValue.getValue())
×
NEW
212
                                                .log();
×
213
                        }
214
                        SETTING_LOG.atInfo()
1✔
215
                                        .setMessage("Enum [name:{}, value:{}] added to parameter.")
1✔
216
                                        .addArgument(fieldName)
1✔
217
                                        .addArgument(newValue.getValue())
1✔
218
                                        .log();
1✔
219
                }
220
        }
1✔
221

222
        /**
223
         * {inheritDoc}
224
         *
225
         * @see ExecutionContextProvider#getConstParamPrefix()
226
         */
227
        @Override
228
        public String getConstParamPrefix() {
229
                return constParamPrefix;
1✔
230
        }
231

232
        /**
233
         * {inheritDoc}
234
         *
235
         * @see ExecutionContextProvider#setConstParamPrefix(String)
236
         */
237
        @Override
238
        public ExecutionContextProvider setConstParamPrefix(final String constParamPrefix) {
239
                this.constParamPrefix = constParamPrefix;
×
240
                return this;
×
241
        }
242

243
        /**
244
         * {inheritDoc}
245
         *
246
         * @see ExecutionContextProvider#getConstantClassNames()
247
         */
248
        @Override
249
        public List<String> getConstantClassNames() {
250
                return constantClassNames;
×
251
        }
252

253
        /**
254
         * {inheritDoc}
255
         *
256
         * @see ExecutionContextProvider#setConstantClassNames(List)
257
         */
258
        @Override
259
        public ExecutionContextProvider setConstantClassNames(final List<String> constantClassNames) {
260
                this.constantClassNames = constantClassNames;
1✔
261
                return this;
1✔
262
        }
263

264
        /**
265
         * {inheritDoc}
266
         *
267
         * @see ExecutionContextProvider#getConstParameterMap()
268
         */
269
        @Override
270
        public Map<String, Parameter> getConstParameterMap() {
271
                return constParameterMap;
1✔
272
        }
273

274
        /**
275
         * {inheritDoc}
276
         *
277
         * @see ExecutionContextProvider#getEnumConstantPackageNames()
278
         */
279
        @Override
280
        public List<String> getEnumConstantPackageNames() {
281
                return enumConstantPackageNames;
×
282
        }
283

284
        /**
285
         * {inheritDoc}
286
         *
287
         * @see ExecutionContextProvider#setEnumConstantPackageNames(List)
288
         */
289
        @Override
290
        public ExecutionContextProvider setEnumConstantPackageNames(final List<String> enumConstantPackageNames) {
291
                this.enumConstantPackageNames = enumConstantPackageNames;
1✔
292
                return this;
1✔
293
        }
294

295
        /**
296
         * {inheritDoc}
297
         *
298
         * @see ExecutionContextProvider#addBindParamMapper(BindParameterMapper)
299
         */
300
        @Override
301
        public ExecutionContextProvider addBindParamMapper(final BindParameterMapper<?> parameterMapper) {
302
                parameterMapperManager.addMapper(parameterMapper);
1✔
303
                return this;
1✔
304
        }
305

306
        /**
307
         * {inheritDoc}
308
         *
309
         * @see ExecutionContextProvider#removeBindParamMapper(BindParameterMapper)
310
         */
311
        @Override
312
        public ExecutionContextProvider removeBindParamMapper(final BindParameterMapper<?> parameterMapper) {
313
                parameterMapperManager.removeMapper(parameterMapper);
×
314
                return this;
×
315
        }
316

317
        /**
318
         * 定数クラスパラメータMap生成
319
         *
320
         * @return 定数クラスパラメータMap
321
         */
322
        private Map<? extends String, ? extends Parameter> buildConstParamMap() {
323
                var paramMap = new HashMap<String, Parameter>();
1✔
324
                for (var className : constantClassNames) {
1✔
325
                        if (ObjectUtils.isNotBlank(className)) {
1✔
326
                                try {
327
                                        var targetClass = Class.forName(className, true, Thread.currentThread().getContextClassLoader());
1✔
328
                                        makeConstParamMap(paramMap, targetClass);
1✔
329
                                } catch (ClassNotFoundException ex) {
×
NEW
330
                                        LOG.atError()
×
NEW
331
                                                        .setMessage(ex.getMessage())
×
NEW
332
                                                        .setCause(ex)
×
NEW
333
                                                        .log();
×
334
                                }
1✔
335
                        }
336
                }
1✔
337
                return paramMap;
1✔
338
        }
339

340
        /**
341
         * Enum定数パラメータMap生成
342
         *
343
         * @return Enum定数パラメータMap
344
         */
345
        private Map<? extends String, ? extends Parameter> buildEnumConstParamMap() {
346
                var paramMap = new HashMap<String, Parameter>();
1✔
347
                for (var packageName : enumConstantPackageNames) {
1✔
348
                        if (ObjectUtils.isNotBlank(packageName)) {
1✔
349
                                for (var targetClass : listUpEnumClasses(packageName)) {
1✔
350
                                        makeEnumConstParamMap(paramMap, packageName, targetClass);
1✔
351
                                }
1✔
352
                        }
353
                }
1✔
354
                return paramMap;
1✔
355
        }
356

357
        /**
358
         * 対象パッケージ以下のクラスを取得
359
         *
360
         * @param packageName ルートパッケージ名
361
         * @return クラスリスト
362
         */
363
        @SuppressWarnings({ "unchecked", "rawtypes" })
364
        private static Set<Class<? extends Enum<?>>> listUpEnumClasses(final String packageName) {
365
                var resourceName = packageName.replace('.', '/');
1✔
366
                var classLoader = Thread.currentThread().getContextClassLoader();
1✔
367
                List<URL> roots;
368
                try {
369
                        roots = Collections.list(classLoader.getResources(resourceName));
1✔
370
                } catch (IOException ex) {
×
NEW
371
                        LOG.atError()
×
NEW
372
                                        .setMessage(ex.getMessage())
×
NEW
373
                                        .setCause(ex)
×
NEW
374
                                        .log();
×
UNCOV
375
                        return Set.of();
×
376
                }
1✔
377

378
                var classes = new HashSet<Class<?>>();
1✔
379
                for (var root : roots) {
1✔
380
                        if ("file".equalsIgnoreCase(root.getProtocol())) {
1✔
381
                                try {
382
                                        classes.addAll(findEnumClassesWithFile(packageName, Paths.get(root.toURI())));
1✔
383
                                } catch (URISyntaxException ex) {
×
NEW
384
                                        LOG.atError()
×
NEW
385
                                                        .setMessage(ex.getMessage())
×
NEW
386
                                                        .setCause(ex)
×
NEW
387
                                                        .log();
×
388
                                }
1✔
389
                        }
390
                        if ("jar".equalsIgnoreCase(root.getProtocol())) {
1✔
391
                                try (var jarFile = ((JarURLConnection) root.openConnection()).getJarFile()) {
1✔
392
                                        classes.addAll(findEnumClassesWithJar(packageName, jarFile));
1✔
393
                                } catch (IOException ex) {
×
NEW
394
                                        LOG.atError()
×
NEW
395
                                                        .setMessage(ex.getMessage())
×
NEW
396
                                                        .setCause(ex)
×
NEW
397
                                                        .log();
×
398
                                }
1✔
399
                        }
400
                }
1✔
401

402
                return (Set) classes;
1✔
403
        }
404

405
        /**
406
         * classファイルから対象パッケージ以下のEnumクラスを取得
407
         *
408
         * @param packageName ルートパッケージ名
409
         * @param dir 対象ディレクトリ
410
         * @return クラスリスト
411
         * @throws ClassNotFoundException エラー
412
         * @throws IOException
413
         */
414
        private static Set<Class<?>> findEnumClassesWithFile(final String packageName, final Path dir) {
415
                var prefix = packageName + ".";
1✔
416
                try (var stream = Files.walk(dir)) {
1✔
417
                        return stream.filter(entry -> entry.getFileName().toString().endsWith(".class"))
1✔
418
                                        .flatMap(file -> {
1✔
419
                                                var joiner = new StringJoiner(".", prefix, "");
1✔
420
                                                dir.relativize(file).forEach(p -> joiner.add(p.toString()));
1✔
421
                                                var className = joiner.toString().replaceAll(".class$", "");
1✔
422
                                                return loadEnum(className).stream();
1✔
423
                                        })
424
                                        .filter(Objects::nonNull)
1✔
425
                                        .collect(Collectors.toSet());
1✔
426
                } catch (IOException ex) {
×
NEW
427
                        LOG.atError()
×
NEW
428
                                        .setMessage(ex.getMessage())
×
NEW
429
                                        .setCause(ex)
×
NEW
430
                                        .log();
×
UNCOV
431
                        return Set.of();
×
432
                }
433
        }
434

435
        /**
436
         * jarファイルから対象パッケージ以下のEnumクラスを取得
437
         *
438
         * @param packageName ルートパッケージ名
439
         * @param jarFile jarファイル
440
         * @return クラスリスト
441
         * @throws ClassNotFoundException エラー
442
         * @throws IOException
443
         */
444
        private static Collection<? extends Class<?>> findEnumClassesWithJar(final String packageName,
445
                        final JarFile jarFile) {
446
                var resourceName = packageName.replace('.', '/');
1✔
447
                return Collections.list(jarFile.entries()).stream()
1✔
448
                                .map(JarEntry::getName)
1✔
449
                                .filter(name -> name.startsWith(resourceName) && name.endsWith(".class"))
1✔
450
                                .map(name -> name.replace('/', '.').replaceAll(".class$", ""))
1✔
451
                                .flatMap(className -> loadEnum(className).stream())
1✔
452
                                .filter(Objects::nonNull)
1✔
453
                                .collect(Collectors.toSet());
1✔
454
        }
455

456
        /**
457
         * Enumクラスをロード<br>
458
         * 指定クラスがEnumでない場合はemptyを返す
459
         *
460
         * @param className クラス名
461
         * @return ロードしたEnumクラス
462
         */
463
        private static Optional<Class<?>> loadEnum(final String className) {
464
                try {
465
                        var type = Class.forName(className, true, Thread.currentThread().getContextClassLoader());
1✔
466
                        if (type.isEnum()) {
1✔
467
                                return Optional.of(type);
1✔
468
                        }
469
                } catch (ClassNotFoundException ex) {
×
NEW
470
                        LOG.atError()
×
NEW
471
                                        .setMessage(ex.getMessage())
×
NEW
472
                                        .setCause(ex)
×
NEW
473
                                        .log();
×
474
                }
1✔
475
                return Optional.empty();
1✔
476
        }
477

478
        /**
479
         * {@inheritDoc}
480
         *
481
         * @see jp.co.future.uroborosql.context.ExecutionContextProvider#setDefaultResultSetType(int)
482
         */
483
        @Override
484
        public ExecutionContextProvider setDefaultResultSetType(final int resultSetType) {
485
                defaultResultSetType = resultSetType;
1✔
486
                return this;
1✔
487
        }
488

489
        /**
490
         * {@inheritDoc}
491
         *
492
         * @see jp.co.future.uroborosql.context.ExecutionContextProvider#setDefaultResultSetConcurrency(int)
493
         */
494
        @Override
495
        public ExecutionContextProvider setDefaultResultSetConcurrency(final int resultSetConcurrency) {
496
                defaultResultSetConcurrency = resultSetConcurrency;
1✔
497
                return this;
1✔
498
        }
499

500
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc