Skip to content

Package: VariableTypeInheritanceSearch

VariableTypeInheritanceSearch

nameinstructionbranchcomplexitylinemethod
VariableTypeInheritanceSearch()
M: 8 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
checkSubclassRuntimeInfo(TypeVariable)
M: 16 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
findParameterizedSuperclass(Type)
M: 28 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
searchParametrizedType(Type, TypeVariable)
M: 28 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 8 C: 0
0%
M: 1 C: 0
0%
searchRuntimeTypeArgument(ParameterizedType, TypeVariable)
M: 42 C: 0
0%
M: 8 C: 0
0%
M: 5 C: 0
0%
M: 10 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*
2: * Copyright (c) 2015, 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.ArrayDeque;
19: import java.util.Deque;
20:
21: import jakarta.json.bind.JsonbException;
22:
23: import org.eclipse.yasson.internal.properties.MessageKeys;
24: import org.eclipse.yasson.internal.properties.Messages;
25:
26: /**
27: * Search for type variable in inheritance hierarchy and resolve if possible.
28: */
29: class VariableTypeInheritanceSearch {
30:
31: private final Deque<ParameterizedType> parameterizedSubclasses = new ArrayDeque<>();
32:
33: /**
34: * Searches the hierarchy of classes to resolve a type variable. If typevar resolved value is another typevar redirection
35: * (propagated from wrapping class),
36: * this typevar is returned.
37: *
38: * <pre>
39: *
40: * Example 1: typevar is resolved
41: *
42: *
43: * class GenericClass <T> {
44: * private T genericField;
45: * }
46: * class ConcreteClass extends GenericClass<MyPojo> {
47: * //...
48: * }
49: *
50: * In above case when ConcreteClass type is passed as runtime type and <T> as type variable, T is resolved to MyPojo.
51: * </pre>
52: *
53: *
54: * <pre>
55: * Example 2: typevar is resolved to another propagated typevar
56: *
57: *
58: * class WrapperGenericClass<X> {
59: * private GenericClass<X> propagatedGenericField
60: * }
61: *
62: * class AnotherClass extends WrapperGenericClass<MyPojo> {
63: * }
64: *
65: *
66: * In second case when GenericClass {@link ParameterizedType} is passed as runtime type and <T> as type variable,
67: * T is resolved to propagated <X> by WrapperGenericClass.
68: *
69: * Resolution on <X> must be performed thereafter with AnotherClass runtime type.
70: * </pre>
71: *
72: * @param typeToSearch runtime type to search for typevar in, not null
73: * @param typeVar type variable to resolve, not null
74: * @return resolved runtime type, or type variable
75: */
76: Type searchParametrizedType(Type typeToSearch, TypeVariable<?> typeVar) {
77: ParameterizedType parameterizedType = findParameterizedSuperclass(typeToSearch);
78:• if (parameterizedType == null) {
79: return null;
80: }
81: Type matchedGenericType = searchRuntimeTypeArgument(parameterizedType, typeVar);
82:• if (matchedGenericType != null) {
83: return matchedGenericType;
84: }
85: parameterizedSubclasses.push(parameterizedType);
86: return searchParametrizedType(((Class) parameterizedType.getRawType()).getGenericSuperclass(), typeVar);
87: }
88:
89: private Type checkSubclassRuntimeInfo(TypeVariable typeVar) {
90:• if (parameterizedSubclasses.size() == 0) {
91: return typeVar;
92: }
93: ParameterizedType parametrizedSubclass = parameterizedSubclasses.pop();
94: return searchRuntimeTypeArgument(parametrizedSubclass, typeVar);
95: }
96:
97: private Type searchRuntimeTypeArgument(ParameterizedType runtimeType, TypeVariable<?> typeVar) {
98:• if (ReflectionUtils.getRawType(runtimeType) != typeVar.getGenericDeclaration()) {
99: return null;
100: }
101: TypeVariable[] bounds = typeVar.getGenericDeclaration().getTypeParameters();
102:• for (int i = 0; i < bounds.length; i++) {
103:• if (bounds[i].equals(typeVar)) {
104: Type matchedGenericType = runtimeType.getActualTypeArguments()[i];
105: //Propagated generic types to another generic classes
106:• if (matchedGenericType instanceof TypeVariable<?>) {
107: return checkSubclassRuntimeInfo((TypeVariable) matchedGenericType);
108: }
109: //found runtime matchedGenericType
110: return matchedGenericType;
111: }
112: }
113: return null;
114: }
115:
116: private static ParameterizedType findParameterizedSuperclass(Type type) {
117:• if (type == null || type instanceof ParameterizedType) {
118: return (ParameterizedType) type;
119: }
120:• if (!(type instanceof Class)) {
121: throw new JsonbException(Messages.getMessage(MessageKeys.RESOLVE_PARAMETRIZED_TYPE, type));
122: }
123: return findParameterizedSuperclass(((Class) type).getGenericSuperclass());
124: }
125: }