Skip to content

Commit 820cf37

Browse files
committed
MCR-3650 refactor MCRConfigurableInstanceHelper into multiple classes
1 parent 8fd24c1 commit 820cf37

28 files changed

+2226
-1731
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ local.properties
9595

9696
## Maven https://github.com/github/gitignore/blob/master/Maven.gitignore
9797
target/
98+
!**/src/**/target/
9899
pom.xml.tag
99100
pom.xml.releaseBackup
100101
pom.xml.versionsBackup

mycore-base/src/main/java/org/mycore/common/config/MCRConfigurableInstanceHelper.java

Lines changed: 15 additions & 1716 deletions
Large diffs are not rendered by default.

mycore-base/src/main/java/org/mycore/common/config/MCRConfiguration2.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import java.util.stream.Stream;
3333

3434
import org.mycore.common.MCRClassTools;
35+
import org.mycore.common.config.instantiator.MCRInstantiator;
3536
import org.mycore.common.function.MCRTriConsumer;
3637

3738
/**
@@ -131,11 +132,11 @@ public static Map<String, String> getSubPropertiesMap(String propertyPrefix) {
131132
* @throws MCRConfigurationException if the class can not be loaded or instantiated
132133
*/
133134
public static <S> Optional<S> getInstanceOf(Class<S> superClass, String name) throws MCRConfigurationException {
134-
return getInstanceOf(superClass, name, MCRConfigurableInstanceHelper.NO_OPTIONS);
135+
return getInstanceOf(superClass, name, MCRInstantiator.NO_OPTIONS);
135136
}
136137

137138
private static <S> Optional<S> getInstanceOf(Class<S> superClass, String name,
138-
Set<MCRConfigurableInstanceHelper.Option> options) {
139+
Set<MCRInstantiator.Option> options) {
139140
if (MCRConfigurableInstanceHelper.isSingleton(superClass)) {
140141
return getSingleInstanceOf(superClass, name, options);
141142
} else {
@@ -153,7 +154,7 @@ private static <S> Optional<S> getInstanceOf(Class<S> superClass, String name,
153154
* or the configuration property is not set
154155
*/
155156
public static <S> S getInstanceOfOrThrow(Class<S> superClass, String name) throws MCRConfigurationException {
156-
return getInstanceOf(superClass, name, MCRConfigurableInstanceHelper.ADD_IMPLICIT_CLASS_PROPERTIES)
157+
return getInstanceOf(superClass, name, MCRInstantiator.ADD_IMPLICIT_CLASS_PROPERTIES_OPTION)
157158
.orElseThrow(() -> createConfigurationException(name));
158159
}
159160

@@ -167,11 +168,11 @@ public static <S> S getInstanceOfOrThrow(Class<S> superClass, String name) throw
167168
* @throws MCRConfigurationException if the class can not be loaded or instantiated
168169
*/
169170
public static <S> Optional<S> getSingleInstanceOf(Class<S> superClass, String name) {
170-
return getSingleInstanceOf(superClass, name, MCRConfigurableInstanceHelper.NO_OPTIONS);
171+
return getSingleInstanceOf(superClass, name, MCRInstantiator.NO_OPTIONS);
171172
}
172173

173174
private static <S> Optional<S> getSingleInstanceOf(Class<S> superClass, String name,
174-
Set<MCRConfigurableInstanceHelper.Option> options) {
175+
Set<MCRInstantiator.Option> options) {
175176
return getString(name)
176177
.map(className -> new ConfigSingletonKey(name, className))
177178
.map(key -> (S) instanceHolder.computeIfAbsent(key,
@@ -189,7 +190,7 @@ private static <S> Optional<S> getSingleInstanceOf(Class<S> superClass, String n
189190
* or the configuration property is not set
190191
*/
191192
public static <S> S getSingleInstanceOfOrThrow(Class<S> superClass, String name) {
192-
return getSingleInstanceOf(superClass, name, MCRConfigurableInstanceHelper.ADD_IMPLICIT_CLASS_PROPERTIES)
193+
return getSingleInstanceOf(superClass, name, MCRInstantiator.ADD_IMPLICIT_CLASS_PROPERTIES_OPTION)
193194
.orElseThrow(() -> createConfigurationException(name));
194195
}
195196

mycore-base/src/main/java/org/mycore/common/config/MCRInstanceConfiguration.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,9 @@ public Map<String, MCRInstanceConfiguration> nestedConfigurationMap() {
389389
* @return the nested configuration map
390390
*/
391391
public Map<String, MCRInstanceConfiguration> nestedConfigurationMap(String commonPrefix) {
392+
if (commonPrefix.isEmpty()) {
393+
return nestedConfigurationMap();
394+
}
392395
String commonSuffixWithDelimiter = commonPrefix + ".";
393396
Map<String, MCRInstanceConfiguration> nestedConfigurationMap = new HashMap<>();
394397
for (Map.Entry<String, String> entry : properties().entrySet()) {

mycore-base/src/main/java/org/mycore/common/config/instantiator/MCRInstantiator.java

Lines changed: 410 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
/*
2+
* This file is part of *** M y C o R e ***
3+
* See https://www.mycore.de/ for details.
4+
*
5+
* MyCoRe is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* MyCoRe is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with MyCoRe. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
package org.mycore.common.config.instantiator;
20+
21+
import java.lang.reflect.Method;
22+
import java.util.ArrayList;
23+
import java.util.List;
24+
import java.util.Locale;
25+
import java.util.Map;
26+
import java.util.Objects;
27+
import java.util.SortedMap;
28+
import java.util.TreeMap;
29+
import java.util.stream.Collectors;
30+
31+
import org.mycore.common.MCRClassTools;
32+
import org.mycore.common.config.MCRConfigurationException;
33+
import org.mycore.common.config.MCRInstanceConfiguration;
34+
import org.mycore.common.config.instantiator.source.MCRSource;
35+
import org.mycore.common.config.instantiator.target.MCRTarget;
36+
37+
/**
38+
* Utility class providing functions commonly used by {@link MCRInstantiator} and related classes.
39+
*/
40+
@SuppressWarnings("PMD.AvoidDuplicateLiterals")
41+
public final class MCRInstantiatorUtils {
42+
43+
private MCRInstantiatorUtils() {
44+
}
45+
46+
@SuppressWarnings("unchecked")
47+
public static <T> Class<T> getClass(String property, String className) {
48+
try {
49+
return (Class<T>) MCRClassTools.forName(className);
50+
} catch (ClassNotFoundException e) {
51+
throw new MCRConfigurationException("Missing class (" + className + ") configured in: " + property, e);
52+
}
53+
}
54+
55+
public static String methodNames(List<Method> methods) {
56+
return methods.stream()
57+
.map(Method::getName)
58+
.collect(Collectors.joining(", "));
59+
}
60+
61+
public static String targetTypeName(MCRTarget target) {
62+
return target.type().name().toLowerCase(Locale.ROOT);
63+
}
64+
65+
public static String annotationClassNames(List<MCRSource> sources) {
66+
return sources.stream()
67+
.map(MCRInstantiatorUtils::annotationClassName)
68+
.collect(Collectors.joining(", "));
69+
}
70+
71+
public static String annotationClassName(MCRSource source) {
72+
return source.annotationClass().getName();
73+
}
74+
75+
public static String property(MCRInstanceConfiguration configuration, String annotationName) {
76+
if (Objects.equals("", annotationName)) {
77+
return configuration.name().canonical();
78+
} else {
79+
return configuration.name().canonical() + "." + annotationName;
80+
}
81+
}
82+
83+
public static MCRConfigurationException emptyNameException(MCRTarget target) {
84+
return new MCRConfigurationException("The name for target " + targetTypeName(target) + " '" + target.name()
85+
+ "' in configured class " + target.declaringClass().getName() + " must not be empty");
86+
}
87+
88+
public static MCRConfigurationException incompatibilityException(String property, MCRTarget target,
89+
Class<?> annotationValueClass, Object instance) {
90+
throw new MCRConfigurationException("Instance of class " + instance.getClass().getName()
91+
+ "', configured in " + property + ", is incompatible with annotated value class "
92+
+ annotationValueClass.getName() + " for target " + targetTypeName(target)
93+
+ " '" + target.name() + "' in configured class " + target.declaringClass().getName());
94+
}
95+
96+
public static MCRConfigurationException missingException(String property, MCRTarget target,
97+
String description) {
98+
throw new MCRConfigurationException(
99+
capitalize(description) + ", configured in " + property + " (and its sub-properties)," +
100+
" for target " + targetTypeName(target) + " '" + target.name() + "' in configured class "
101+
+ target.declaringClass().getName()
102+
+ " is missing");
103+
}
104+
105+
public static MCRConfigurationException emptyException(String property, MCRTarget target, String description) {
106+
throw new MCRConfigurationException(
107+
capitalize(description) + ", configured in " + property + " (and its sub-properties)," +
108+
" for target " + targetTypeName(target) + " '" + target.name() + "' in configured class "
109+
+ target.declaringClass().getName()
110+
+ " is empty");
111+
}
112+
113+
public static MCRConfigurationException emptyRawException(String property, MCRTarget target,
114+
String description) {
115+
throw new MCRConfigurationException(
116+
capitalize(description) + ", configured in " + property + "," +
117+
" for target " + targetTypeName(target) + " '" + target.name() + "' in configured class "
118+
+ target.declaringClass().getName()
119+
+ " is empty");
120+
}
121+
122+
public static MCRConfigurationException nonIntegerKeyException(String property, MCRTarget target,
123+
String key, String description) {
124+
return new MCRConfigurationException(
125+
capitalize(description) + ", configured in " + property + " (and its sub-properties)," +
126+
" for target " + targetTypeName(target) + " '" + target.name() + "' in configured class "
127+
+ target.declaringClass().getName() + " is has element with non-integer key " + key);
128+
}
129+
130+
public static String capitalize(String description) {
131+
return description.substring(0, 1).toUpperCase(Locale.ROOT) + description.substring(1);
132+
}
133+
134+
public static MCRConfigurationException inconsistentKeysException(String property, MCRTarget target,
135+
String key1, String key2, String description) {
136+
return new MCRConfigurationException(
137+
capitalize(description) + ", configured in " + property + " (and its sub-properties),"
138+
+ " for target " + targetTypeName(target) + " '" + target.name() + "' in configured class "
139+
+ target.declaringClass().getName() + " has element with inconsistent integer keys "
140+
+ key1 + " and " + key2);
141+
}
142+
143+
@SuppressWarnings("PMD.PreserveStackTrace")
144+
public static List<String> orderedKeys(String property, MCRTarget target, Map<String, ?> map,
145+
String description) {
146+
147+
SortedMap<Integer, String> keyMap = new TreeMap<>();
148+
for (String key : map.keySet()) {
149+
try {
150+
Integer integerValue = Integer.parseInt(key);
151+
String alreadyMappedKey = keyMap.put(integerValue, key);
152+
if (alreadyMappedKey != null && !alreadyMappedKey.equals(key)) {
153+
throw inconsistentKeysException(property, target, key, alreadyMappedKey, description);
154+
}
155+
} catch (NumberFormatException e) {
156+
throw nonIntegerKeyException(property, target, key, description);
157+
}
158+
}
159+
160+
return new ArrayList<>(keyMap.values());
161+
162+
}
163+
164+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* This file is part of *** M y C o R e ***
3+
* See https://www.mycore.de/ for details.
4+
*
5+
* MyCoRe is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* MyCoRe is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with MyCoRe. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
package org.mycore.common.config.instantiator.injectable;
20+
21+
import java.lang.reflect.Field;
22+
import java.util.Optional;
23+
24+
import org.mycore.common.config.instantiator.source.MCRSource;
25+
import org.mycore.common.config.instantiator.source.MCRSourceType;
26+
import org.mycore.common.config.instantiator.target.MCRFieldTarget;
27+
import org.mycore.common.config.instantiator.target.MCRTarget;
28+
29+
/**
30+
* A {@link MCRFieldInjectable} is a {@link MCRFieldInjectable} that abstracts a {@link Field}.
31+
*/
32+
public final class MCRFieldInjectable implements MCRInjectable {
33+
34+
private final Field field;
35+
36+
public MCRFieldInjectable(Field field) {
37+
this.field = field;
38+
}
39+
40+
@Override
41+
public Optional<MCRSource> toSource(MCRSourceType sourceType) {
42+
return sourceType.toSource(field::getAnnotation);
43+
}
44+
45+
@Override
46+
public MCRTarget toTarget() {
47+
return new MCRFieldTarget(field);
48+
}
49+
50+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* This file is part of *** M y C o R e ***
3+
* See https://www.mycore.de/ for details.
4+
*
5+
* MyCoRe is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* MyCoRe is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with MyCoRe. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
package org.mycore.common.config.instantiator.injectable;
20+
21+
import java.lang.reflect.Field;
22+
import java.lang.reflect.Method;
23+
import java.util.Optional;
24+
25+
import org.mycore.common.config.instantiator.source.MCRSource;
26+
import org.mycore.common.config.instantiator.source.MCRSourceType;
27+
import org.mycore.common.config.instantiator.target.MCRTarget;
28+
29+
/**
30+
* Common abstraction for components of a class (i.e., a {@link Field} or a {@link Method}) that can,
31+
* in principle, be used for injection. It provides abstractions for obtaining a value ({@link MCRSource})
32+
* based on present annotations, and injecting obtained values ({@link MCRTarget}).
33+
*/
34+
public interface MCRInjectable {
35+
36+
Optional<MCRSource> toSource(MCRSourceType sourceType);
37+
38+
MCRTarget toTarget();
39+
40+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* This file is part of *** M y C o R e ***
3+
* See https://www.mycore.de/ for details.
4+
*
5+
* MyCoRe is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* MyCoRe is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with MyCoRe. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
package org.mycore.common.config.instantiator.injectable;
20+
21+
import java.lang.reflect.Method;
22+
import java.util.Optional;
23+
24+
import org.mycore.common.config.instantiator.source.MCRSource;
25+
import org.mycore.common.config.instantiator.source.MCRSourceType;
26+
import org.mycore.common.config.instantiator.target.MCRMethodTarget;
27+
import org.mycore.common.config.instantiator.target.MCRTarget;
28+
29+
/**
30+
* A {@link MCRFieldInjectable} is a {@link MCRFieldInjectable} that abstracts a {@link Method}.
31+
*/
32+
public final class MCRMethodInjectable implements MCRInjectable {
33+
34+
private final Method method;
35+
36+
public MCRMethodInjectable(Method method) {
37+
this.method = method;
38+
}
39+
40+
@Override
41+
public Optional<MCRSource> toSource(MCRSourceType sourceType) {
42+
return sourceType.toSource(method::getAnnotation);
43+
}
44+
45+
@Override
46+
public MCRTarget toTarget() {
47+
return new MCRMethodTarget(method);
48+
}
49+
50+
}

0 commit comments

Comments
 (0)