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

ljacqu / JavaTypeResolver / 5964916055

24 Aug 2023 02:14PM UTC coverage: 97.658% (-0.2%) from 97.874%
5964916055

push

github

ljacqu
#96 Create SerializableType

612 of 643 branches covered (0.0%)

Branch coverage included in aggregate %.

72 of 72 new or added lines in 1 file covered. (100.0%)

1181 of 1193 relevant lines covered (98.99%)

4.81 hits per line

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

93.75
/src/main/java/ch/jalu/typeresolver/serialize/SerializableType.java
1
package ch.jalu.typeresolver.serialize;
2

3
import ch.jalu.typeresolver.CommonTypeUtils;
4
import ch.jalu.typeresolver.typeimpl.GenericArrayTypeImpl;
5
import ch.jalu.typeresolver.typeimpl.ParameterizedTypeImpl;
6
import ch.jalu.typeresolver.typeimpl.WildcardTypeImpl;
7

8
import java.io.Serializable;
9
import java.lang.reflect.GenericArrayType;
10
import java.lang.reflect.GenericDeclaration;
11
import java.lang.reflect.ParameterizedType;
12
import java.lang.reflect.Type;
13
import java.lang.reflect.TypeVariable;
14
import java.lang.reflect.WildcardType;
15
import java.util.Arrays;
16

17
/**
18
 * Represents a {@link Type} in a serializable manner.
19
 * Create a serializable type with {@link SerializableType#from}, convert back with {@link SerializableType#getType}.
20
 * <p>
21
 * Limitations:<ul>
22
 *  <li>An exception is thrown for type variables that aren't declared by a class (see Javadoc on
23
 *     {@link SerializableTypeVariable} for more information).</li>
24
 *  <li>An exception is thrown if the Type is not of any standard subtype: {@link Class}, {@link GenericArrayType},
25
 *      {@link ParameterizedType}, {@link TypeVariable} or {@link WildcardType}.</li>
26
 * </ul>
27
 */
28
public abstract class SerializableType implements Serializable {
3✔
29

30
    private transient Type type;
31

32
    /**
33
     * @return the type wrapped by this instance
34
     */
35
    public Type getType() {
36
        if (type == null) {
×
37
            type = toType();
×
38
        }
39
        return type;
×
40
    }
41

42
    /**
43
     * Returns a {@link SerializableType} representing the given type.
44
     *
45
     * @param type the type to map
46
     * @return serializable type representing the given type
47
     */
48
    public static SerializableType from(Type type) {
49
        if (type == null) {
2✔
50
            return null;
2✔
51
        } else if (type instanceof Class<?>) {
3✔
52
             return new ClassWrapper((Class<?>) type);
6✔
53
        } else if (type instanceof ParameterizedType) {
3✔
54
            return SerializableParameterizedType.from((ParameterizedType) type);
4✔
55
        } else if (type instanceof TypeVariable<?>) {
3✔
56
            return SerializableTypeVariable.from((TypeVariable<?>) type);
4✔
57
        } else if (type instanceof GenericArrayType) {
3✔
58
            return SerializableGenericArrayType.from((GenericArrayType) type);
4✔
59
        } else if (type instanceof WildcardType) {
3✔
60
            return SerializableWildcardType.from((WildcardType) type);
4✔
61
        }
62

63
        throw new IllegalArgumentException("Unknown type implementation: " + type.getClass());
13✔
64
    }
65

66
    /**
67
     * @return creates the Type this object represents
68
     */
69
    protected abstract Type toType();
70

71
    private static SerializableType[] convertTypes(Type[] types) {
72
        return Arrays.stream(types)
4✔
73
            .map(SerializableType::from)
2✔
74
            .toArray(SerializableType[]::new);
5✔
75
    }
76

77
    private static Type[] convertSerializableTypes(SerializableType[] serTypes) {
78
        return Arrays.stream(serTypes)
4✔
79
            .map(SerializableType::toType)
2✔
80
            .toArray(Type[]::new);
5✔
81
    }
82

83
    /**
84
     * SerializableType impl. that wraps a Class (Class is already serializable).
85
     */
86
    public static class ClassWrapper extends SerializableType {
87
        private static final long serialVersionUID = 1;
88

89
        private final Class<?> clazz;
90

91
        public ClassWrapper(Class<?> clazz) {
2✔
92
            this.clazz = clazz;
3✔
93
        }
1✔
94

95
        @Override
96
        public Class<?> toType() {
97
            return clazz;
3✔
98
        }
99
    }
100

101
    /**
102
     * SerializableType impl. for parameterized types.
103
     */
104
    public static class SerializableParameterizedType extends SerializableType {
105
        private static final long serialVersionUID = 1;
106

107
        private final Class<?> rawType;
108
        private final SerializableType[] actualTypeArguments;
109
        private final SerializableType ownerType;
110

111
        public SerializableParameterizedType(Class<?> rawType,
112
                                             SerializableType[] actualTypeArguments,
113
                                             SerializableType ownerType) {
2✔
114
            this.rawType = rawType;
3✔
115
            this.actualTypeArguments = actualTypeArguments;
3✔
116
            this.ownerType = ownerType;
3✔
117
        }
1✔
118

119
        public static SerializableParameterizedType from(ParameterizedType pt) {
120
            SerializableType ownerType = SerializableType.from(pt.getOwnerType());
4✔
121
            SerializableType[] typeArgs = convertTypes(pt.getActualTypeArguments());
4✔
122
            return new SerializableParameterizedType(CommonTypeUtils.getRawType(pt), typeArgs, ownerType);
8✔
123
        }
124

125
        @Override
126
        public ParameterizedType toType() {
127
            Type[] actualTypeArgs = convertSerializableTypes(actualTypeArguments);
4✔
128
            Type owner = ownerType == null ? null : ownerType.toType();
6!
129
            return new ParameterizedTypeImpl(rawType, owner, actualTypeArgs);
8✔
130
        }
131
    }
132

133
    /**
134
     * SerializableType impl. for generic array types.
135
     */
136
    public static class SerializableGenericArrayType extends SerializableType {
137
        private static final long serialVersionUID = 1;
138

139
        private final SerializableType genericComponentType;
140

141
        public SerializableGenericArrayType(SerializableType componentType) {
2✔
142
            this.genericComponentType = componentType;
3✔
143
        }
1✔
144

145
        public static SerializableGenericArrayType from(GenericArrayType gat) {
146
            return new SerializableGenericArrayType(from(gat.getGenericComponentType()));
7✔
147
        }
148

149
        @Override
150
        public GenericArrayType toType() {
151
            return new GenericArrayTypeImpl(genericComponentType.toType());
7✔
152
        }
153
    }
154

155
    /**
156
     * SerializableType impl. for type variables. Only type variables from classes are supported; an exception is
157
     * thrown for type variables of methods or constructors.
158
     * <p>
159
     * Background: The internal implementation of {@link TypeVariable} in the JDK only considers objects equal to each
160
     * other that implement that same class. As such, we cannot create instances of another class and rely on resolving
161
     * the type variable back based on the class declaring it and the type variable's index in the declaring class's
162
     * type variables.
163
     */
164
    public static class SerializableTypeVariable extends SerializableType {
165
        private static final long serialVersionUID = 1;
166

167
        private final Class<?> origin;
168
        private final int index;
169

170
        public SerializableTypeVariable(Class<?> origin, int index) {
2✔
171
            this.origin = origin;
3✔
172
            this.index = index;
3✔
173
        }
1✔
174

175
        /**
176
         * Creates a SerializableType for the given type variable. An exception is thrown for type variables that
177
         * aren't declared by a class (see Javadoc on {@link SerializableTypeVariable} for more information).
178
         *
179
         * @param tv the type variable to map
180
         * @return serializable representation of the type variable
181
         */
182
        public static SerializableTypeVariable from(TypeVariable<?> tv) {
183
            GenericDeclaration declarer = tv.getGenericDeclaration();
3✔
184
            if (declarer instanceof Class<?>) {
3✔
185
                int index = findIndex(declarer, tv);
4✔
186
                return new SerializableTypeVariable((Class<?>) declarer, index);
7✔
187
            } else {
188
                throw new IllegalArgumentException(
12✔
189
                    "Type variable must be declared by a class, but found declarer: " + declarer);
190
            }
191
        }
192

193
        @Override
194
        public TypeVariable<?> toType() {
195
            TypeVariable<? extends Class<?>>[] typeParams = origin.getTypeParameters();
4✔
196
            if (index >= typeParams.length) {
5✔
197
                throw new IllegalStateException("No type variable at index " + index + " for " + origin);
18✔
198
            }
199
            return typeParams[index];
5✔
200
        }
201

202
        private static int findIndex(GenericDeclaration declarer, TypeVariable<?> type) {
203
            int index = 0;
2✔
204
            for (TypeVariable<?> typeParameter : declarer.getTypeParameters()) {
17✔
205
                if (typeParameter.equals(type)) {
4✔
206
                    return index;
2✔
207
                }
208
                ++index;
1✔
209
            }
210

211
            throw new IllegalArgumentException("Type variable '" + type + "' does not belong to " + declarer);
16✔
212
        }
213
    }
214

215
    /**
216
     * SerializableType impl. for wildcard types.
217
     */
218
    public static class SerializableWildcardType extends SerializableType {
219
        private static final long serialVersionUID = 1;
220

221
        private final SerializableType[] upperBounds;
222
        private final SerializableType[] lowerBounds;
223

224
        public SerializableWildcardType(SerializableType[] upperBounds, SerializableType[] lowerBounds) {
2✔
225
            this.upperBounds = upperBounds;
3✔
226
            this.lowerBounds = lowerBounds;
3✔
227
        }
1✔
228

229
        public static SerializableWildcardType from(WildcardType wt) {
230
            SerializableType[] upperBounds = convertTypes(wt.getUpperBounds());
4✔
231
            SerializableType[] lowerBounds = convertTypes(wt.getLowerBounds());
4✔
232
            return new SerializableWildcardType(upperBounds, lowerBounds);
6✔
233
        }
234

235
        @Override
236
        public WildcardType toType() {
237
            Type[] upperBounds = convertSerializableTypes(this.upperBounds);
4✔
238
            Type[] lowerBounds = convertSerializableTypes(this.lowerBounds);
4✔
239
            return new WildcardTypeImpl(upperBounds, lowerBounds);
6✔
240
        }
241
    }
242
}
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