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

future-architect / uroborosql / #715

pending completion
#715

push

web-flow
merge v0.x changes to master (#310)

* v0.x to master merge

* fix nanoseconds diff (java8 to java11)

* eclipse cleanup and  optimize import

* eclipse format

* optimize Imports

* remove unused annotation

* library version up

* migrate v0.x to master
- update java version 8 to 11
- update junit4 to junit5
- library version update

* fix test failed

* remove unused annotation

* fixed bug

* use var

* fix java8 coding style

1154 of 1154 new or added lines in 77 files covered. (100.0%)

7721 of 8533 relevant lines covered (90.48%)

0.9 hits per line

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

85.56
/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.function.Consumer;
32
import java.util.jar.JarEntry;
33
import java.util.jar.JarFile;
34
import java.util.stream.Collectors;
35

36
import org.slf4j.Logger;
37
import org.slf4j.LoggerFactory;
38

39
import jp.co.future.uroborosql.config.SqlConfig;
40
import jp.co.future.uroborosql.parameter.Parameter;
41
import jp.co.future.uroborosql.parameter.mapper.BindParameterMapper;
42
import jp.co.future.uroborosql.parameter.mapper.BindParameterMapperManager;
43
import jp.co.future.uroborosql.utils.CaseFormat;
44
import jp.co.future.uroborosql.utils.StringUtils;
45

46
/**
47
 * ExecutionContextプロバイダ実装
48
 *
49
 * @author H.Sugimoto
50
 */
51
public class ExecutionContextProviderImpl implements ExecutionContextProvider {
1✔
52
        /** ロガー */
53
        private static final Logger LOG = LoggerFactory.getLogger("jp.co.future.uroborosql.log");
1✔
54

55
        /** 設定ロガー */
56
        private static final Logger SETTING_LOG = LoggerFactory.getLogger("jp.co.future.uroborosql.setting");
1✔
57

58
        /** 定数パラメータプレフィックス */
59
        private String constParamPrefix = "CLS_";
1✔
60

61
        /** 定数クラス名(FQDN) */
62
        private List<String> constantClassNames = new ArrayList<>();
1✔
63
        /** Enum定数パッケージ名 */
64
        private List<String> enumConstantPackageNames = new ArrayList<>();
1✔
65

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

69
        /** SQL設定クラス */
70
        private SqlConfig sqlConfig = null;
1✔
71

72
        /** 自動パラメータバインド関数List(query用) */
73
        private final List<Consumer<ExecutionContext>> queryAutoParameterBinders = new ArrayList<>();
1✔
74

75
        /** 自動パラメータバインド関数List(update/batch/proc用) */
76
        private final List<Consumer<ExecutionContext>> updateAutoParameterBinders = new ArrayList<>();
1✔
77

78
        /** 合成自動パラメータバインド関数(query用) */
79
        private Consumer<ExecutionContext> queryAutoParameterBinder = null;
1✔
80

81
        /** 合成自動パラメータバインド関数(update/batch/proc用) */
82
        private Consumer<ExecutionContext> updateAutoParameterBinder = null;
1✔
83

84
        /** ResultSetTypeの初期値 */
85
        private int defaultResultSetType = ResultSet.TYPE_FORWARD_ONLY;
1✔
86

87
        /** ResultSetConcurrencyの初期値*/
88
        private int defaultResultSetConcurrency = ResultSet.CONCUR_READ_ONLY;
1✔
89

90
        /** パラメータ変換マネージャ */
91
        private BindParameterMapperManager parameterMapperManager = new BindParameterMapperManager(
1✔
92
                        Clock.systemDefaultZone());
1✔
93

94
        /**
95
         * {@inheritDoc}
96
         *
97
         * @see jp.co.future.uroborosql.context.ExecutionContextProvider#createExecutionContext()
98
         */
99
        @Override
100
        public ExecutionContext createExecutionContext() {
101
                var executionContext = new ExecutionContextImpl();
1✔
102
                var paramMap = new ConcurrentHashMap<>(getConstParameterMap());
1✔
103

104
                executionContext.setConstParameterMap(paramMap);
1✔
105
                executionContext.setSqlFilterManager(getSqlConfig().getSqlFilterManager());
1✔
106
                executionContext.setParameterMapperManager(
1✔
107
                                new BindParameterMapperManager(parameterMapperManager, getSqlConfig().getClock()));
1✔
108
                executionContext.setQueryAutoParameterBinder(queryAutoParameterBinder);
1✔
109
                executionContext.setUpdateAutoParameterBinder(updateAutoParameterBinder);
1✔
110
                executionContext.setResultSetType(defaultResultSetType);
1✔
111
                executionContext.setResultSetConcurrency(defaultResultSetConcurrency);
1✔
112

113
                return executionContext;
1✔
114
        }
115

116
        /**
117
         * {@inheritDoc}
118
         *
119
         * @see jp.co.future.uroborosql.config.SqlConfigAware#setSqlConfig(jp.co.future.uroborosql.config.SqlConfig)
120
         */
121
        @Override
122
        public void setSqlConfig(final SqlConfig sqlConfig) {
123
                this.sqlConfig = sqlConfig;
1✔
124
        }
1✔
125

126
        /**
127
         * {@inheritDoc}
128
         *
129
         * @see jp.co.future.uroborosql.config.SqlConfigAware#getSqlConfig()
130
         */
131
        @Override
132
        public SqlConfig getSqlConfig() {
133
                return sqlConfig;
1✔
134
        }
135

136
        /**
137
         * {@inheritDoc}
138
         *
139
         * @see jp.co.future.uroborosql.context.ExecutionContextProvider#initialize()
140
         */
141
        @Override
142
        public void initialize() {
143
                parameterMapperManager = new BindParameterMapperManager(parameterMapperManager, getSqlConfig().getClock());
1✔
144

145
                var paramMap = new HashMap<String, Parameter>(buildConstParamMap());
1✔
146
                paramMap.putAll(buildEnumConstParamMap());
1✔
147
                constParameterMap = Collections.unmodifiableMap(paramMap);
1✔
148
        }
1✔
149

150
        /**
151
         * 定数パラメータのMapを生成する
152
         *
153
         * @param paramMap 定数パラメータを保持するMap
154
         * @param targetClass 定数パラメータを生成する定数クラス。クラス内に内部クラスを持つ場合は内部クラスの定数フィールドもパラメータに登録する
155
         */
156
        protected void makeConstParamMap(final Map<String, Parameter> paramMap, final Class<?> targetClass) {
157
                try {
158
                        var fieldPrefix = targetClass.isMemberClass() ? CaseFormat.UPPER_SNAKE_CASE
1✔
159
                                        .convert(targetClass.getSimpleName()) + "_" : "";
1✔
160
                        // 指定されたクラス直下の定数フィールドを追加
161
                        var fields = targetClass.getFields();
1✔
162
                        for (var field : fields) {
1✔
163
                                var mod = field.getModifiers();
1✔
164
                                if (Modifier.isFinal(mod) && Modifier.isStatic(mod)) {
1✔
165
                                        var value = field.get(null);
1✔
166
                                        if (parameterMapperManager.canAcceptByStandard(value)) {
1✔
167
                                                var fieldName = getConstParamPrefix() + fieldPrefix + field.getName();
1✔
168
                                                fieldName = fieldName.toUpperCase();
1✔
169
                                                var newValue = new Parameter(fieldName, field.get(null));
1✔
170
                                                var prevValue = paramMap.put(fieldName, newValue);
1✔
171
                                                if (prevValue != null) {
1✔
172
                                                        SETTING_LOG.warn("Duplicate constant name. Constant name:{}, old value:{} destroy.",
×
173
                                                                        fieldName,
174
                                                                        prevValue.getValue());
×
175
                                                }
176
                                                SETTING_LOG.info("Constant [name:{}, value:{}] added to parameter.",
1✔
177
                                                                fieldName,
178
                                                                newValue.getValue());
1✔
179
                                        }
180
                                }
181
                        }
182

183
                        // 内部クラスを持つ場合
184
                        var memberClasses = targetClass.getDeclaredClasses();
1✔
185
                        for (var memberClass : memberClasses) {
1✔
186
                                var mod = memberClass.getModifiers();
1✔
187
                                if (Modifier.isFinal(mod) && Modifier.isPublic(mod)) {
1✔
188
                                        makeConstParamMap(paramMap, memberClass);
1✔
189
                                }
190
                        }
191
                } catch (IllegalArgumentException | IllegalAccessException | SecurityException ex) {
×
192
                        LOG.error(ex.getMessage(), ex);
×
193
                }
1✔
194
        }
1✔
195

196
        /**
197
         * Enum型の定数パラメータのMapを生成する
198
         *
199
         * @param paramMap 定数パラメータを保持するMap
200
         * @param packageName パッケージ名
201
         * @param targetClass 対象Enumクラス
202
         */
203
        protected void makeEnumConstParamMap(final Map<String, Parameter> paramMap, final String packageName,
204
                        final Class<? extends Enum<?>> targetClass) {
205

206
                var fieldPrefix = CaseFormat.UPPER_SNAKE_CASE.convert(targetClass.getName().substring(
1✔
207
                                packageName.length() + 1))
1✔
208
                                + "_";
209

210
                var enumValues = targetClass.getEnumConstants();
1✔
211

212
                for (var value : enumValues) {
1✔
213
                        var fieldName = (getConstParamPrefix() + fieldPrefix + value.name().toUpperCase()).toUpperCase();
1✔
214
                        var newValue = new Parameter(fieldName, value);
1✔
215
                        var prevValue = paramMap.put(fieldName, newValue);
1✔
216
                        if (prevValue != null) {
1✔
217
                                SETTING_LOG.warn("Duplicate Enum name. Enum name:{}, old value:{} destroy.",
×
218
                                                fieldName,
219
                                                prevValue.getValue());
×
220
                        }
221
                        SETTING_LOG.info("Enum [name:{}, value:{}] added to parameter.",
1✔
222
                                        fieldName,
223
                                        newValue.getValue());
1✔
224
                }
225
        }
1✔
226

227
        /**
228
         * {inheritDoc}
229
         *
230
         * @see ExecutionContextProvider#getConstParamPrefix()
231
         */
232
        @Override
233
        public String getConstParamPrefix() {
234
                return constParamPrefix;
1✔
235
        }
236

237
        /**
238
         * {inheritDoc}
239
         *
240
         * @see ExecutionContextProvider#setConstParamPrefix(String)
241
         */
242
        @Override
243
        public ExecutionContextProvider setConstParamPrefix(final String constParamPrefix) {
244
                this.constParamPrefix = constParamPrefix;
×
245
                return this;
×
246
        }
247

248
        /**
249
         * {inheritDoc}
250
         *
251
         * @see ExecutionContextProvider#getConstantClassNames()
252
         */
253
        @Override
254
        public List<String> getConstantClassNames() {
255
                return constantClassNames;
×
256
        }
257

258
        /**
259
         * {inheritDoc}
260
         *
261
         * @see ExecutionContextProvider#setConstantClassNames(List)
262
         */
263
        @Override
264
        public ExecutionContextProvider setConstantClassNames(final List<String> constantClassNames) {
265
                this.constantClassNames = constantClassNames;
1✔
266
                return this;
1✔
267
        }
268

269
        /**
270
         * {inheritDoc}
271
         *
272
         * @see ExecutionContextProvider#getConstParameterMap()
273
         */
274
        @Override
275
        public Map<String, Parameter> getConstParameterMap() {
276
                return constParameterMap;
1✔
277
        }
278

279
        /**
280
         * {inheritDoc}
281
         *
282
         * @see ExecutionContextProvider#getEnumConstantPackageNames()
283
         */
284
        @Override
285
        public List<String> getEnumConstantPackageNames() {
286
                return enumConstantPackageNames;
×
287
        }
288

289
        /**
290
         * {inheritDoc}
291
         *
292
         * @see ExecutionContextProvider#setEnumConstantPackageNames(List)
293
         */
294
        @Override
295
        public ExecutionContextProvider setEnumConstantPackageNames(final List<String> enumConstantPackageNames) {
296
                this.enumConstantPackageNames = enumConstantPackageNames;
1✔
297
                return this;
1✔
298
        }
299

300
        /**
301
         * {inheritDoc}
302
         *
303
         * @see ExecutionContextProvider#addBindParamMapper(BindParameterMapper)
304
         */
305
        @Override
306
        public ExecutionContextProvider addBindParamMapper(final BindParameterMapper<?> parameterMapper) {
307
                parameterMapperManager.addMapper(parameterMapper);
1✔
308
                return this;
1✔
309
        }
310

311
        /**
312
         * {inheritDoc}
313
         *
314
         * @see ExecutionContextProvider#removeBindParamMapper(BindParameterMapper)
315
         */
316
        @Override
317
        public ExecutionContextProvider removeBindParamMapper(final BindParameterMapper<?> parameterMapper) {
318
                parameterMapperManager.removeMapper(parameterMapper);
×
319
                return this;
×
320
        }
321

322
        /**
323
         * {@inheritDoc}
324
         *
325
         * @see jp.co.future.uroborosql.context.ExecutionContextProvider#addQueryAutoParameterBinder(java.util.function.Consumer)
326
         */
327
        @Override
328
        public ExecutionContextProvider addQueryAutoParameterBinder(final Consumer<ExecutionContext> binder) {
329
                queryAutoParameterBinders.add(binder);
1✔
330
                queryAutoParameterBinder = queryAutoParameterBinders.stream()
1✔
331
                                .reduce(Consumer::andThen)
1✔
332
                                .orElse(null);
1✔
333
                return this;
1✔
334
        }
335

336
        /**
337
         * {@inheritDoc}
338
         *
339
         * @see jp.co.future.uroborosql.context.ExecutionContextProvider#removeQueryAutoParameterBinder(java.util.function.Consumer)
340
         */
341
        @Override
342
        public ExecutionContextProvider removeQueryAutoParameterBinder(final Consumer<ExecutionContext> binder) {
343
                queryAutoParameterBinders.remove(binder);
1✔
344
                queryAutoParameterBinder = queryAutoParameterBinders.stream()
1✔
345
                                .reduce(Consumer::andThen)
1✔
346
                                .orElse(null);
1✔
347
                return this;
1✔
348
        }
349

350
        /**
351
         * {@inheritDoc}
352
         *
353
         * @see jp.co.future.uroborosql.context.ExecutionContextProvider#addUpdateAutoParameterBinder(java.util.function.Consumer)
354
         */
355
        @Override
356
        public ExecutionContextProvider addUpdateAutoParameterBinder(final Consumer<ExecutionContext> binder) {
357
                updateAutoParameterBinders.add(binder);
1✔
358
                updateAutoParameterBinder = updateAutoParameterBinders.stream()
1✔
359
                                .reduce(Consumer::andThen)
1✔
360
                                .orElse(null);
1✔
361
                return this;
1✔
362
        }
363

364
        /**
365
         * {@inheritDoc}
366
         *
367
         * @see jp.co.future.uroborosql.context.ExecutionContextProvider#removeUpdateAutoParameterBinder(java.util.function.Consumer)
368
         */
369
        @Override
370
        public ExecutionContextProvider removeUpdateAutoParameterBinder(final Consumer<ExecutionContext> binder) {
371
                updateAutoParameterBinders.remove(binder);
1✔
372
                updateAutoParameterBinder = updateAutoParameterBinders.stream()
1✔
373
                                .reduce(Consumer::andThen)
1✔
374
                                .orElse(null);
1✔
375
                return this;
1✔
376
        }
377

378
        /**
379
         * 定数クラスパラメータMap生成
380
         *
381
         * @return 定数クラスパラメータMap
382
         */
383
        private Map<? extends String, ? extends Parameter> buildConstParamMap() {
384
                var paramMap = new HashMap<String, Parameter>();
1✔
385
                for (var className : constantClassNames) {
1✔
386
                        if (StringUtils.isNotBlank(className)) {
1✔
387
                                try {
388
                                        var targetClass = Class.forName(className, true, Thread.currentThread().getContextClassLoader());
1✔
389
                                        makeConstParamMap(paramMap, targetClass);
1✔
390
                                } catch (ClassNotFoundException ex) {
×
391
                                        LOG.error(ex.getMessage(), ex);
×
392
                                }
1✔
393
                        }
394
                }
1✔
395
                return paramMap;
1✔
396
        }
397

398
        /**
399
         * Enum定数パラメータMap生成
400
         *
401
         * @return Enum定数パラメータMap
402
         */
403
        private Map<? extends String, ? extends Parameter> buildEnumConstParamMap() {
404
                var paramMap = new HashMap<String, Parameter>();
1✔
405
                for (var packageName : enumConstantPackageNames) {
1✔
406
                        if (StringUtils.isNotBlank(packageName)) {
1✔
407
                                for (var targetClass : listupEnumClasses(packageName)) {
1✔
408
                                        makeEnumConstParamMap(paramMap, packageName, targetClass);
1✔
409
                                }
1✔
410
                        }
411
                }
1✔
412
                return paramMap;
1✔
413
        }
414

415
        /**
416
         * 対象パッケージ以下のクラスを取得
417
         *
418
         * @param packageName ルートパッケージ名
419
         * @return クラスリスト
420
         */
421
        @SuppressWarnings({ "unchecked", "rawtypes" })
422
        private static Set<Class<? extends Enum<?>>> listupEnumClasses(final String packageName) {
423
                var resourceName = packageName.replace('.', '/');
1✔
424
                var classLoader = Thread.currentThread().getContextClassLoader();
1✔
425
                List<URL> roots;
426
                try {
427
                        roots = Collections.list(classLoader.getResources(resourceName));
1✔
428
                } catch (IOException e) {
×
429
                        LOG.error(e.getMessage(), e);
×
430
                        return Set.of();
×
431
                }
1✔
432

433
                var classes = new HashSet<Class<?>>();
1✔
434
                for (var root : roots) {
1✔
435
                        if ("file".equalsIgnoreCase(root.getProtocol())) {
1✔
436
                                try {
437
                                        classes.addAll(findEnumClassesWithFile(packageName, Paths.get(root.toURI())));
1✔
438
                                } catch (URISyntaxException e) {
×
439
                                        LOG.error(e.getMessage(), e);
×
440
                                }
1✔
441
                        }
442
                        if ("jar".equalsIgnoreCase(root.getProtocol())) {
1✔
443
                                try (var jarFile = ((JarURLConnection) root.openConnection()).getJarFile()) {
1✔
444
                                        classes.addAll(findEnumClassesWithJar(packageName, jarFile));
1✔
445
                                } catch (IOException e) {
×
446
                                        LOG.error(e.getMessage(), e);
×
447
                                }
1✔
448
                        }
449
                }
1✔
450

451
                return (Set) classes;
1✔
452
        }
453

454
        /**
455
         * classファイルから対象パッケージ以下のEnumクラスを取得
456
         *
457
         * @param packageName ルートパッケージ名
458
         * @param dir 対象ディレクトリ
459
         * @return クラスリスト
460
         * @throws ClassNotFoundException エラー
461
         * @throws IOException
462
         */
463
        private static Set<Class<?>> findEnumClassesWithFile(final String packageName, final Path dir) {
464
                var prefix = packageName + ".";
1✔
465
                try (var stream = Files.walk(dir)) {
1✔
466
                        return stream.filter(entry -> entry.getFileName().toString().endsWith(".class"))
1✔
467
                                        .flatMap(file -> {
1✔
468
                                                var joiner = new StringJoiner(".", prefix, "");
1✔
469
                                                dir.relativize(file).forEach(p -> joiner.add(p.toString()));
1✔
470
                                                var className = joiner.toString().replaceAll(".class$", "");
1✔
471
                                                return loadEnum(className).stream();
1✔
472
                                        })
473
                                        .filter(Objects::nonNull)
1✔
474
                                        .collect(Collectors.toSet());
1✔
475
                } catch (IOException e) {
×
476
                        LOG.error(e.getMessage(), e);
×
477
                        return Set.of();
×
478
                }
479
        }
480

481
        /**
482
         * jarファイルから対象パッケージ以下のEnumクラスを取得
483
         *
484
         * @param packageName ルートパッケージ名
485
         * @param jarFile jarファイル
486
         * @return クラスリスト
487
         * @throws ClassNotFoundException エラー
488
         * @throws IOException
489
         */
490
        private static Collection<? extends Class<?>> findEnumClassesWithJar(final String packageName,
491
                        final JarFile jarFile) {
492
                var resourceName = packageName.replace('.', '/');
1✔
493
                return Collections.list(jarFile.entries()).stream()
1✔
494
                                .map(JarEntry::getName)
1✔
495
                                .filter(name -> name.startsWith(resourceName) && name.endsWith(".class"))
1✔
496
                                .map(name -> name.replace('/', '.').replaceAll(".class$", ""))
1✔
497
                                .flatMap(className -> loadEnum(className).stream())
1✔
498
                                .filter(Objects::nonNull)
1✔
499
                                .collect(Collectors.toSet());
1✔
500
        }
501

502
        /**
503
         * Enumクラスをロード<br>
504
         * 指定クラスがEnumでない場合はemptyを返す
505
         *
506
         * @param className クラス名
507
         * @return ロードしたEnumクラス
508
         */
509
        private static Optional<Class<?>> loadEnum(final String className) {
510
                try {
511
                        var type = Class.forName(className, true, Thread.currentThread().getContextClassLoader());
1✔
512
                        if (type.isEnum()) {
1✔
513
                                return Optional.of(type);
1✔
514
                        }
515
                } catch (ClassNotFoundException e) {
×
516
                        LOG.error(e.getMessage(), e);
×
517
                }
1✔
518
                return Optional.empty();
1✔
519
        }
520

521
        /**
522
         * {@inheritDoc}
523
         *
524
         * @see jp.co.future.uroborosql.context.ExecutionContextProvider#setDefaultResultSetType(int)
525
         */
526
        @Override
527
        public ExecutionContextProvider setDefaultResultSetType(final int resultSetType) {
528
                defaultResultSetType = resultSetType;
1✔
529
                return this;
1✔
530
        }
531

532
        /**
533
         * {@inheritDoc}
534
         *
535
         * @see jp.co.future.uroborosql.context.ExecutionContextProvider#setDefaultResultSetConcurrency(int)
536
         */
537
        @Override
538
        public ExecutionContextProvider setDefaultResultSetConcurrency(final int resultSetConcurrency) {
539
                defaultResultSetConcurrency = resultSetConcurrency;
1✔
540
                return this;
1✔
541
        }
542

543
}
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