Skip to content

Package: ComponentMatcher

ComponentMatcher

nameinstructionbranchcomplexitylinemethod
ComponentMatcher(JsonbContext)
M: 16 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
addAdapter(Type, AdapterBinding)
M: 10 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
addDeserializer(Type, DeserializerBinding)
M: 10 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
addSerializer(Type, SerializerBinding)
M: 10 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
getBindingInfo(Type)
M: 7 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
getDeserializeAdapterBinding(Type, ComponentBoundCustomization)
M: 14 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
getDeserializerBinding(Type, ComponentBoundCustomization)
M: 14 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
getMatchingBinding(Type, ComponentBindings, Function)
M: 17 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
getSerializeAdapterBinding(Type, ComponentBoundCustomization)
M: 14 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
getSerializerBinding(Type, ComponentBoundCustomization)
M: 14 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
init()
M: 109 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 16 C: 0
0%
M: 1 C: 0
0%
introspectAdapterBinding(Class, JsonbAdapter)
M: 56 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 12 C: 0
0%
M: 1 C: 0
0%
introspectDeserializerBinding(Class, JsonbDeserializer)
M: 45 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 10 C: 0
0%
M: 1 C: 0
0%
introspectSerializerBinding(Class, JsonbSerializer)
M: 45 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 9 C: 0
0%
M: 1 C: 0
0%
lambda$addAdapter$6(Type, AdapterBinding, Type, ComponentBindings)
M: 18 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
lambda$addDeserializer$5(Type, DeserializerBinding, Type, ComponentBindings)
M: 18 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
lambda$addSerializer$4(Type, SerializerBinding, Type, ComponentBindings)
M: 18 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
lambda$getBindingInfo$3(Type, ComponentBindings)
M: 9 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
lambda$init$0()
M: 3 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
lambda$init$1()
M: 3 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
lambda$init$2()
M: 3 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
matchTypeArguments(ParameterizedType, ParameterizedType)
M: 35 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 9 C: 0
0%
M: 1 C: 0
0%
matches(Type, Type)
M: 46 C: 0
0%
M: 16 C: 0
0%
M: 9 C: 0
0%
M: 9 C: 0
0%
M: 1 C: 0
0%
registerGeneric(Type)
M: 10 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
resolveTypeArg(Type, Type)
M: 27 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
searchComponentBinding(Type, Function)
M: 85 C: 0
0%
M: 18 C: 0
0%
M: 10 C: 0
0%
M: 19 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*
2: * Copyright (c) 2016, 2022 Oracle and/or its affiliates. All rights reserved.
3: *
4: * This program and the accompanying materials are made available under the
5: * terms of the Eclipse Public License v. 2.0 which is available at
6: * http://www.eclipse.org/legal/epl-2.0,
7: * or the Eclipse Distribution License v. 1.0 which is available at
8: * http://www.eclipse.org/org/documents/edl-v10.php.
9: *
10: * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
11: */
12:
13: package org.eclipse.yasson.internal;
14:
15: import java.lang.reflect.ParameterizedType;
16: import java.lang.reflect.Type;
17: import java.lang.reflect.TypeVariable;
18: import java.util.LinkedList;
19: import java.util.Objects;
20: import java.util.Optional;
21: import java.util.concurrent.ConcurrentHashMap;
22: import java.util.concurrent.ConcurrentMap;
23: import java.util.function.Function;
24:
25: import jakarta.json.bind.JsonbConfig;
26: import jakarta.json.bind.adapter.JsonbAdapter;
27: import jakarta.json.bind.serializer.JsonbDeserializer;
28: import jakarta.json.bind.serializer.JsonbSerializer;
29:
30: import org.eclipse.yasson.internal.components.AbstractComponentBinding;
31: import org.eclipse.yasson.internal.components.AdapterBinding;
32: import org.eclipse.yasson.internal.components.ComponentBindings;
33: import org.eclipse.yasson.internal.components.DeserializerBinding;
34: import org.eclipse.yasson.internal.components.SerializerBinding;
35: import org.eclipse.yasson.internal.model.customization.ComponentBoundCustomization;
36:
37: /**
38: * Searches for a registered components or Serializer for a given type.
39: */
40: public class ComponentMatcher {
41:
42: private final JsonbContext jsonbContext;
43:
44: /**
45: * Flag for searching for generic serializers and adapters in runtime.
46: */
47: private volatile boolean genericComponents;
48:
49: private final ConcurrentMap<Type, ComponentBindings> userComponents;
50:
51: /**
52: * Create component matcher.
53: *
54: * @param context mandatory
55: */
56: ComponentMatcher(JsonbContext context) {
57: Objects.requireNonNull(context);
58: this.jsonbContext = context;
59: userComponents = new ConcurrentHashMap<>();
60: init();
61: }
62:
63: /**
64: * Called during context creation, introspecting user components provided with JsonbConfig.
65: */
66: void init() {
67: final JsonbSerializer<?>[] serializers = (JsonbSerializer<?>[]) jsonbContext.getConfig()
68: .getProperty(JsonbConfig.SERIALIZERS).orElseGet(() -> new JsonbSerializer<?>[] {});
69:• for (JsonbSerializer<?> serializer : serializers) {
70: SerializerBinding<?> serializerBinding = introspectSerializerBinding(serializer.getClass(), serializer);
71: addSerializer(serializerBinding.getBindingType(), serializerBinding);
72: }
73: final JsonbDeserializer<?>[] deserializers = (JsonbDeserializer<?>[]) jsonbContext.getConfig()
74: .getProperty(JsonbConfig.DESERIALIZERS).orElseGet(() -> new JsonbDeserializer<?>[] {});
75:• for (JsonbDeserializer<?> deserializer : deserializers) {
76: DeserializerBinding<?> deserializerBinding = introspectDeserializerBinding(deserializer.getClass(), deserializer);
77: addDeserializer(deserializerBinding.getBindingType(), deserializerBinding);
78: }
79:
80: final JsonbAdapter<?, ?>[] adapters = (JsonbAdapter<?, ?>[]) jsonbContext.getConfig().getProperty(JsonbConfig.ADAPTERS)
81: .orElseGet(() -> new JsonbAdapter<?, ?>[] {});
82:• for (JsonbAdapter<?, ?> adapter : adapters) {
83: AdapterBinding adapterBinding = introspectAdapterBinding(adapter.getClass(), adapter);
84: addAdapter(adapterBinding.getBindingType(), adapterBinding);
85: }
86: }
87:
88: private ComponentBindings getBindingInfo(Type type) {
89: return userComponents
90:• .compute(type, (type1, bindingInfo) -> bindingInfo != null ? bindingInfo : new ComponentBindings(type1));
91: }
92:
93: private void addSerializer(Type bindingType, SerializerBinding<?> serializer) {
94: userComponents.computeIfPresent(bindingType, (type, bindings) -> {
95:• if (bindings.getSerializer() != null) {
96: return bindings;
97: }
98: registerGeneric(bindingType);
99: return new ComponentBindings(bindingType, serializer, bindings.getDeserializer(), bindings.getAdapterInfo());
100: });
101: }
102:
103: private void addDeserializer(Type bindingType, DeserializerBinding<?> deserializer) {
104: userComponents.computeIfPresent(bindingType, (type, bindings) -> {
105:• if (bindings.getDeserializer() != null) {
106: return bindings;
107: }
108: registerGeneric(bindingType);
109: return new ComponentBindings(bindingType, bindings.getSerializer(), deserializer, bindings.getAdapterInfo());
110: });
111: }
112:
113: private void addAdapter(Type bindingType, AdapterBinding adapter) {
114: userComponents.computeIfPresent(bindingType, (type, bindings) -> {
115:• if (bindings.getAdapterInfo() != null) {
116: return bindings;
117: }
118: registerGeneric(bindingType);
119: return new ComponentBindings(bindingType, bindings.getSerializer(), bindings.getDeserializer(), adapter);
120: });
121: }
122:
123: /**
124: * If type is not parametrized runtime component resolution doesn't has to happen.
125: *
126: * @param bindingType component binding type
127: */
128: private void registerGeneric(Type bindingType) {
129:• if (bindingType instanceof ParameterizedType && !genericComponents) {
130: genericComponents = true;
131: }
132: }
133:
134: /**
135: * Lookup serializer binding for a given property runtime type.
136: *
137: * @param propertyRuntimeType runtime type of a property
138: * @param customization with component info
139: * @return serializer optional
140: */
141: public Optional<SerializerBinding<?>> getSerializerBinding(Type propertyRuntimeType,
142: ComponentBoundCustomization customization) {
143:
144:• if (customization == null || customization.getSerializerBinding() == null) {
145: return searchComponentBinding(propertyRuntimeType, ComponentBindings::getSerializer);
146: }
147: return Optional.of(customization.getSerializerBinding());
148: }
149:
150: /**
151: * Lookup deserializer binding for a given property runtime type.
152: *
153: * @param propertyRuntimeType runtime type of a property
154: * @param customization customization with component info
155: * @return serializer optional
156: */
157: public Optional<DeserializerBinding<?>> getDeserializerBinding(Type propertyRuntimeType,
158: ComponentBoundCustomization customization) {
159:• if (customization == null || customization.getDeserializerBinding() == null) {
160: return searchComponentBinding(propertyRuntimeType, ComponentBindings::getDeserializer);
161: }
162: return Optional.of(customization.getDeserializerBinding());
163: }
164:
165: /**
166: * Get components from property model (if declared by annotation and runtime type matches),
167: * or return components searched by runtime type.
168: *
169: * @param propertyRuntimeType runtime type not null
170: * @param customization customization with component info
171: * @return components info if present
172: */
173: public Optional<AdapterBinding> getSerializeAdapterBinding(Type propertyRuntimeType,
174: ComponentBoundCustomization customization) {
175:• if (customization == null || customization.getSerializeAdapterBinding() == null) {
176: return searchComponentBinding(propertyRuntimeType, ComponentBindings::getAdapterInfo);
177: }
178: return Optional.of(customization.getSerializeAdapterBinding());
179: }
180:
181: /**
182: * Get components from property model (if declared by annotation and runtime type matches),
183: * or return components searched by runtime type.
184: *
185: * @param propertyRuntimeType runtime type not null
186: * @param customization customization with component info
187: * @return components info if present
188: */
189: public Optional<AdapterBinding> getDeserializeAdapterBinding(Type propertyRuntimeType,
190: ComponentBoundCustomization customization) {
191:• if (customization == null || customization.getDeserializeAdapterBinding() == null) {
192: return searchComponentBinding(propertyRuntimeType, ComponentBindings::getAdapterInfo);
193: }
194: return Optional.of(customization.getDeserializeAdapterBinding());
195: }
196:
197: private <T extends AbstractComponentBinding> Optional<T> searchComponentBinding(Type runtimeType, Function<ComponentBindings, T> supplier) {
198: // First check if there is an exact match
199: ComponentBindings binding = userComponents.get(runtimeType);
200:• if (binding != null) {
201: Optional<T> match = getMatchingBinding(runtimeType, binding, supplier);
202:• if (match.isPresent()) {
203: return match;
204: }
205: }
206:
207: Optional<Class<?>> runtimeClass = ReflectionUtils.getOptionalRawType(runtimeType);
208:• if (runtimeClass.isPresent()) {
209: // Check if any interfaces have a match
210:• for (Class<?> ifc : runtimeClass.get().getInterfaces()) {
211: ComponentBindings ifcBinding = userComponents.get(ifc);
212:• if (ifcBinding != null) {
213: Optional<T> match = getMatchingBinding(ifc, ifcBinding, supplier);
214:• if (match.isPresent()) {
215: return match;
216: }
217: }
218: }
219:
220: // check if the superclass has a match
221: Class<?> superClass = runtimeClass.get().getSuperclass();
222:• if (superClass != null && superClass != Object.class) {
223: Optional<T> superBinding = searchComponentBinding(superClass, supplier);
224:• if (superBinding.isPresent()) {
225: return superBinding;
226: }
227: }
228: }
229:
230: return Optional.empty();
231: }
232:
233: private <T> Optional<T> getMatchingBinding(Type runtimeType, ComponentBindings binding, Function<ComponentBindings, T> supplier) {
234: final T component = supplier.apply(binding);
235:• if (component != null && matches(runtimeType, binding.getBindingType())) {
236: return Optional.of(component);
237: }
238: return Optional.empty();
239: }
240:
241: private boolean matches(Type runtimeType, Type componentBindingType) {
242:• if (componentBindingType.equals(runtimeType)) {
243: return true;
244: }
245:
246:• if (componentBindingType instanceof Class && runtimeType instanceof Class) {
247: return ((Class<?>) componentBindingType).isAssignableFrom((Class<?>) runtimeType);
248: }
249:
250: //don't try to runtime generic scan if not needed
251:• if (!genericComponents) {
252: return false;
253: }
254:
255:• return runtimeType instanceof ParameterizedType && componentBindingType instanceof ParameterizedType
256:• && ReflectionUtils.getRawType(componentBindingType).isAssignableFrom(ReflectionUtils.getRawType(runtimeType))
257:• && matchTypeArguments((ParameterizedType) runtimeType, (ParameterizedType) componentBindingType);
258: }
259:
260: /**
261: * If runtimeType to adapt is a ParametrizedType, check all type args to match against components args.
262: */
263: private boolean matchTypeArguments(ParameterizedType requiredType, ParameterizedType componentBound) {
264: final Type[] requiredTypeArguments = requiredType.getActualTypeArguments();
265: final Type[] adapterBoundTypeArguments = componentBound.getActualTypeArguments();
266:• if (requiredTypeArguments.length != adapterBoundTypeArguments.length) {
267: return false;
268: }
269:• for (int i = 0; i < requiredTypeArguments.length; i++) {
270: Type adapterTypeArgument = adapterBoundTypeArguments[i];
271:• if (!requiredTypeArguments[i].equals(adapterTypeArgument)) {
272: return false;
273: }
274: }
275: return true;
276: }
277:
278: /**
279: * Introspect components generic information and put resolved types into metadata wrapper.
280: *
281: * @param adapterClass class of an components
282: * @param instance components instance
283: * @return introspected info with resolved typevar types.
284: */
285: AdapterBinding introspectAdapterBinding(Class<? extends JsonbAdapter> adapterClass, JsonbAdapter instance) {
286: final ParameterizedType adapterRuntimeType = ReflectionUtils.findParameterizedType(adapterClass, JsonbAdapter.class);
287: final Type[] adapterTypeArguments = adapterRuntimeType.getActualTypeArguments();
288: Type adaptFromType = resolveTypeArg(adapterTypeArguments[0], adapterClass);
289: Type adaptToType = resolveTypeArg(adapterTypeArguments[1], adapterClass);
290: final ComponentBindings componentBindings = getBindingInfo(adaptFromType);
291:• if (componentBindings.getAdapterInfo() != null && componentBindings.getAdapterInfo().getAdapter().getClass()
292:• .equals(adapterClass)) {
293: return componentBindings.getAdapterInfo();
294: }
295:• JsonbAdapter newAdapter = instance != null
296: ? instance
297: : jsonbContext.getComponentInstanceCreator().getOrCreateComponent(adapterClass);
298: return new AdapterBinding(adaptFromType, adaptToType, newAdapter);
299: }
300:
301: /**
302: * If an instance of deserializerClass is present in context and is bound for same type, return that instance.
303: * Otherwise create new instance and set it to context.
304: *
305: * @param deserializerClass class of deserializer
306: * @param instance instance to use if not cached already
307: * @return wrapper used in property models
308: */
309: @SuppressWarnings("unchecked")
310: DeserializerBinding introspectDeserializerBinding(Class<? extends JsonbDeserializer> deserializerClass,
311: JsonbDeserializer instance) {
312: final ParameterizedType deserializerRuntimeType = ReflectionUtils
313: .findParameterizedType(deserializerClass, JsonbDeserializer.class);
314: Type deserializerBindingType = resolveTypeArg(deserializerRuntimeType.getActualTypeArguments()[0], deserializerClass);
315: final ComponentBindings componentBindings = getBindingInfo(deserializerBindingType);
316:• if (componentBindings.getDeserializer() != null && componentBindings.getDeserializer().getClass()
317:• .equals(deserializerClass)) {
318: return componentBindings.getDeserializer();
319: } else {
320:• JsonbDeserializer deserializer = instance != null ? instance : jsonbContext.getComponentInstanceCreator()
321: .getOrCreateComponent(deserializerClass);
322: return new DeserializerBinding(deserializerBindingType, deserializer);
323: }
324: }
325:
326: /**
327: * If an instance of serializerClass is present in context and is bound for same type, return that instance.
328: * Otherwise create new instance and set it to context.
329: *
330: * @param serializerClass class of deserializer
331: * @param instance instance to use if not cached
332: * @return wrapper used in property models
333: */
334: @SuppressWarnings("unchecked")
335: SerializerBinding introspectSerializerBinding(Class<? extends JsonbSerializer> serializerClass, JsonbSerializer instance) {
336: final ParameterizedType serializerRuntimeType = ReflectionUtils
337: .findParameterizedType(serializerClass, JsonbSerializer.class);
338: Type serBindingType = resolveTypeArg(serializerRuntimeType.getActualTypeArguments()[0], serializerClass);
339: final ComponentBindings componentBindings = getBindingInfo(serBindingType);
340:• if (componentBindings.getSerializer() != null && componentBindings.getSerializer().getClass().equals(serializerClass)) {
341: return componentBindings.getSerializer();
342: } else {
343:• JsonbSerializer serializer = instance != null ? instance : jsonbContext.getComponentInstanceCreator()
344: .getOrCreateComponent(serializerClass);
345: return new SerializerBinding(serBindingType, serializer);
346: }
347:
348: }
349:
350: private Type resolveTypeArg(Type adapterTypeArg, Type adapterType) {
351:• if (adapterTypeArg instanceof ParameterizedType) {
352: return ReflectionUtils.resolveTypeArguments((ParameterizedType) adapterTypeArg, adapterType);
353:• } else if (adapterTypeArg instanceof TypeVariable) {
354: LinkedList<Type> chain = new LinkedList<>();
355: chain.add(adapterType);
356: return ReflectionUtils.resolveItemVariableType(chain, (TypeVariable<?>) adapterTypeArg, true);
357: } else {
358: return adapterTypeArg;
359: }
360: }
361:
362: }