Skip to content

Package: AnnotationIntrospector

AnnotationIntrospector

nameinstructionbranchcomplexitylinemethod
AnnotationIntrospector(JsonbContext)
M: 13 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
addIfNotPresent(JsonbAnnotatedElement, Class, Annotation[])
M: 33 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
checkDuplicityPolymorphicPropertyNames(TypeInheritanceConfiguration)
M: 44 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 15 C: 0
0%
M: 1 C: 0
0%
checkTransientIncompatible(JsonbAnnotatedElement)
M: 31 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 8 C: 0
0%
M: 1 C: 0
0%
collectAnnotations(Class)
M: 72 C: 0
0%
M: 16 C: 0
0%
M: 9 C: 0
0%
M: 15 C: 0
0%
M: 1 C: 0
0%
collectFromInterfaces(Class, Class, Map)
M: 36 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
collectInterfaceAnnotations(Class, Class)
M: 80 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 13 C: 0
0%
M: 1 C: 0
0%
collectInterfaces(Class)
M: 30 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
createJsonbCreator(Executable, JsonbCreator, Class)
M: 75 C: 0
0%
M: 8 C: 0
0%
M: 5 C: 0
0%
M: 11 C: 0
0%
M: 1 C: 0
0%
createJsonbDateFormatter(String, String, Property)
M: 89 C: 0
0%
M: 14 C: 0
0%
M: 8 C: 0
0%
M: 17 C: 0
0%
M: 1 C: 0
0%
findAnnotation(Annotation[], Class)
M: 7 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getAdapterBinding(JsonbAnnotatedElement)
M: 22 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
getAdapterBinding(Parameter)
M: 25 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
getAdapterBinding(Property)
M: 24 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
getAdapterBindingFromAnnotation(JsonbTypeAdapter, Optional)
M: 41 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 8 C: 0
0%
M: 1 C: 0
0%
getAnnotationFromParameterType(Parameter, Class)
M: 13 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
getAnnotationFromProperty(Class, Property)
M: 35 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 10 C: 0
0%
M: 1 C: 0
0%
getAnnotationFromPropertyCategorized(Class, Property)
M: 45 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 11 C: 0
0%
M: 1 C: 0
0%
getAnnotationFromPropertyType(Property, Class)
M: 19 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
getConstructorDateFormatter(JsonbAnnotatedElement)
M: 9 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
getConstructorNumberFormatter(JsonbAnnotatedElement)
M: 9 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
getCreator(Class)
M: 121 C: 0
0%
M: 16 C: 0
0%
M: 9 C: 0
0%
M: 20 C: 0
0%
M: 1 C: 0
0%
getDeserializerBinding(JsonbAnnotatedElement)
M: 24 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
getDeserializerBinding(Parameter)
M: 28 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 8 C: 0
0%
M: 1 C: 0
0%
getDeserializerBinding(Property)
M: 27 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
getFieldAnnotation(Class, JsonbAnnotatedElement)
M: 10 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
getImplementationClass(Property)
M: 12 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
getJsonNumberFormatter(Property)
M: 36 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 8 C: 0
0%
M: 1 C: 0
0%
getJsonbDateFormat(JsonbAnnotatedElement)
M: 25 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
getJsonbDateFormatCategorized(Property)
M: 71 C: 0
0%
M: 12 C: 0
0%
M: 7 C: 0
0%
M: 17 C: 0
0%
M: 1 C: 0
0%
getJsonbNumberFormat(JsonbAnnotatedElement)
M: 19 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
getJsonbPropertyCustomizedName(Property, JsonbAnnotatedElement)
M: 33 C: 0
0%
M: 8 C: 0
0%
M: 5 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
getJsonbPropertyJsonReadName(Property)
M: 9 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
getJsonbPropertyJsonWriteName(Property)
M: 9 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
getJsonbTransientCategorized(Property)
M: 23 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
getMethodAnnotation(Class, JsonbAnnotatedElement)
M: 10 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
getPolymorphismConfig(JsonbAnnotatedElement, ClassCustomization)
M: 121 C: 0
0%
M: 16 C: 0
0%
M: 9 C: 0
0%
M: 29 C: 0
0%
M: 1 C: 0
0%
getPropertyOrder(JsonbAnnotatedElement)
M: 14 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
getPropertyVisibilityStrategy(Class)
M: 34 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
getSerializerBinding(JsonbAnnotatedElement)
M: 24 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
getSerializerBinding(Property)
M: 27 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
introspectCustomization(JsonbAnnotatedElement, ClassCustomization)
M: 52 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 12 C: 0
0%
M: 1 C: 0
0%
isClassNillable(JsonbAnnotatedElement)
M: 35 C: 0
0%
M: 10 C: 0
0%
M: 6 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
isPropertyNillable(Property)
M: 24 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
lambda$collectInterfaceAnnotations$10(Class)
M: 4 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
lambda$collectInterfaceAnnotations$11(Map, Map.Entry)
M: 14 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
lambda$collectInterfaceAnnotations$12(Map, Map.Entry)
M: 11 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
lambda$collectInterfaceAnnotations$13(Class)
M: 4 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
lambda$collectInterfaceAnnotations$14(Class)
M: 4 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
lambda$collectInterfaceAnnotations$15(Map, Map, Map.Entry)
M: 25 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
lambda$getAdapterBinding$0(Property)
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
lambda$getAdapterBinding$3(Parameter)
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
lambda$getAnnotationFromParameterType$4(Class, Class)
M: 8 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
lambda$getConstructorDateFormatter$9(JsonbDateFormat)
M: 14 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
lambda$getConstructorNumberFormatter$8(JsonbNumberFormat)
M: 8 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
lambda$getDeserializerBinding$1(Property)
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
lambda$getDeserializerBinding$2(Parameter)
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
lambda$getJsonNumberFormatter$7(Map, AnnotationTarget, JsonbNumberFormat)
M: 12 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
lambda$getJsonbDateFormatCategorized$6(Map, Property, AnnotationTarget, JsonbDateFormat)
M: 12 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
lambda$getSerializerBinding$5(Property)
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
requiredParameters(Executable, JsonbAnnotatedElement)
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
static {...}
M: 32 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 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.annotation.Annotation;
16: import java.lang.reflect.Constructor;
17: import java.lang.reflect.Executable;
18: import java.lang.reflect.Field;
19: import java.lang.reflect.Method;
20: import java.lang.reflect.Modifier;
21: import java.lang.reflect.Parameter;
22: import java.security.AccessController;
23: import java.security.PrivilegedAction;
24: import java.time.format.DateTimeFormatter;
25: import java.time.format.DateTimeFormatterBuilder;
26: import java.time.temporal.ChronoField;
27: import java.time.temporal.TemporalAccessor;
28: import java.util.Arrays;
29: import java.util.Calendar;
30: import java.util.Date;
31: import java.util.EnumSet;
32: import java.util.HashMap;
33: import java.util.HashSet;
34: import java.util.LinkedHashSet;
35: import java.util.LinkedList;
36: import java.util.List;
37: import java.util.ListIterator;
38: import java.util.Locale;
39: import java.util.Map;
40: import java.util.Objects;
41: import java.util.Optional;
42: import java.util.OptionalDouble;
43: import java.util.OptionalInt;
44: import java.util.OptionalLong;
45: import java.util.Queue;
46: import java.util.Set;
47:
48: import jakarta.json.bind.JsonbException;
49: import jakarta.json.bind.adapter.JsonbAdapter;
50: import jakarta.json.bind.annotation.JsonbDateFormat;
51: import jakarta.json.bind.annotation.JsonbNillable;
52: import jakarta.json.bind.annotation.JsonbNumberFormat;
53: import jakarta.json.bind.annotation.JsonbProperty;
54: import jakarta.json.bind.annotation.JsonbPropertyOrder;
55: import jakarta.json.bind.annotation.JsonbSubtype;
56: import jakarta.json.bind.annotation.JsonbTransient;
57: import jakarta.json.bind.annotation.JsonbTypeAdapter;
58: import jakarta.json.bind.annotation.JsonbTypeDeserializer;
59: import jakarta.json.bind.annotation.JsonbTypeInfo;
60: import jakarta.json.bind.annotation.JsonbTypeSerializer;
61: import jakarta.json.bind.annotation.JsonbVisibility;
62: import jakarta.json.bind.config.PropertyVisibilityStrategy;
63: import jakarta.json.bind.serializer.JsonbDeserializer;
64: import jakarta.json.bind.serializer.JsonbSerializer;
65:
66: import org.eclipse.yasson.ImplementationClass;
67: import org.eclipse.yasson.internal.components.AdapterBinding;
68: import org.eclipse.yasson.internal.components.DeserializerBinding;
69: import org.eclipse.yasson.internal.components.SerializerBinding;
70: import org.eclipse.yasson.internal.model.AnnotationTarget;
71: import org.eclipse.yasson.internal.model.CreatorModel;
72: import org.eclipse.yasson.internal.model.JsonbAnnotatedElement;
73: import org.eclipse.yasson.internal.model.JsonbAnnotatedElement.AnnotationWrapper;
74: import org.eclipse.yasson.internal.model.JsonbCreator;
75: import org.eclipse.yasson.internal.model.Property;
76: import org.eclipse.yasson.internal.model.customization.ClassCustomization;
77: import org.eclipse.yasson.internal.model.customization.TypeInheritanceConfiguration;
78: import org.eclipse.yasson.internal.properties.MessageKeys;
79: import org.eclipse.yasson.internal.properties.Messages;
80:
81: /**
82: * Introspects configuration on classes and their properties by reading annotations.
83: */
84: public class AnnotationIntrospector {
85:
86: // private static final Set<Class<?>> OPTIONALS = Set.of(Optional.class,
87: // OptionalInt.class,
88: // OptionalLong.class,
89: // OptionalDouble.class);
90:
91: private final JsonbContext jsonbContext;
92: private final ConstructorPropertiesAnnotationIntrospector constructorPropertiesIntrospector;
93:
94: private static final Set<Class<? extends Annotation>> REPEATABLE = Set.of(JsonbTypeInfo.class);
95:
96: /**
97: * Annotations to report exception when used in combination with {@link JsonbTransient}.
98: */
99: private static final List<Class<? extends Annotation>> TRANSIENT_INCOMPATIBLE =
100: Arrays.asList(JsonbDateFormat.class, JsonbNumberFormat.class, JsonbProperty.class,
101: JsonbTypeAdapter.class, JsonbTypeSerializer.class, JsonbTypeDeserializer.class);
102:
103: /**
104: * Creates annotation introspecting component passing {@link JsonbContext} inside.
105: *
106: * @param jsonbContext mandatory
107: */
108: public AnnotationIntrospector(JsonbContext jsonbContext) {
109: Objects.requireNonNull(jsonbContext);
110: this.jsonbContext = jsonbContext;
111: this.constructorPropertiesIntrospector = ConstructorPropertiesAnnotationIntrospector.forContext(jsonbContext);
112: }
113:
114: /**
115: * Gets a name of property for JSON marshalling.
116: * Can be different writeName for same property.
117: *
118: * @param property property representation - field, getter, setter (not null)
119: * @return read name
120: */
121: public String getJsonbPropertyJsonWriteName(Property property) {
122: Objects.requireNonNull(property);
123: return getJsonbPropertyCustomizedName(property, property.getGetterElement());
124: }
125:
126: /**
127: * Gets a name of property for JSON unmarshalling.
128: * Can be different from writeName for same property.
129: *
130: * @param property property representation - field, getter, setter (not null)
131: * @return write name
132: */
133: public String getJsonbPropertyJsonReadName(Property property) {
134: Objects.requireNonNull(property);
135: return getJsonbPropertyCustomizedName(property, property.getSetterElement());
136: }
137:
138: private String getJsonbPropertyCustomizedName(Property property, JsonbAnnotatedElement<Method> methodElement) {
139: JsonbProperty methodAnnotation = getMethodAnnotation(JsonbProperty.class, methodElement);
140:• if (methodAnnotation != null && !methodAnnotation.value().isEmpty()) {
141: return methodAnnotation.value();
142: }
143: //in case of property name getter/setter override field value
144: JsonbProperty fieldAnnotation = getFieldAnnotation(JsonbProperty.class, property.getFieldElement());
145:• if (fieldAnnotation != null && !fieldAnnotation.value().isEmpty()) {
146: return fieldAnnotation.value();
147: }
148:
149: return null;
150: }
151:
152: /**
153: * Searches for JsonbCreator annotation on constructors and static methods.
154: *
155: * @param clazz class to search
156: * @return JsonbCreator metadata object
157: */
158: public JsonbCreator getCreator(Class<?> clazz) {
159: JsonbCreator jsonbCreator = null;
160: Constructor<?>[] declaredConstructors =
161: AccessController.doPrivileged((PrivilegedAction<Constructor<?>[]>) clazz::getDeclaredConstructors);
162:
163:• for (Constructor<?> constructor : declaredConstructors) {
164: final jakarta.json.bind.annotation.JsonbCreator annot = findAnnotation(constructor.getDeclaredAnnotations(),
165: jakarta.json.bind.annotation.JsonbCreator.class);
166:• if (annot != null) {
167: jsonbCreator = createJsonbCreator(constructor, jsonbCreator, clazz);
168: }
169: }
170:
171: Method[] declaredMethods =
172: AccessController.doPrivileged((PrivilegedAction<Method[]>) clazz::getDeclaredMethods);
173:• for (Method method : declaredMethods) {
174: final jakarta.json.bind.annotation.JsonbCreator annot = findAnnotation(method.getDeclaredAnnotations(),
175: jakarta.json.bind.annotation.JsonbCreator.class);
176:• if (annot != null && Modifier.isStatic(method.getModifiers())) {
177:• if (!clazz.equals(method.getReturnType())) {
178: throw new JsonbException(Messages.getMessage(MessageKeys.INCOMPATIBLE_FACTORY_CREATOR_RETURN_TYPE,
179: method,
180: clazz));
181: }
182: jsonbCreator = createJsonbCreator(method, jsonbCreator, clazz);
183: }
184: }
185:• if (jsonbCreator == null) {
186: jsonbCreator = ClassMultiReleaseExtension.findCreator(clazz, declaredConstructors, this);
187:• if (jsonbCreator == null) {
188: jsonbCreator = constructorPropertiesIntrospector.getCreator(declaredConstructors);
189: }
190: }
191: return jsonbCreator;
192: }
193:
194: JsonbCreator createJsonbCreator(Executable executable, JsonbCreator existing, Class<?> clazz) {
195:• if (existing != null) {
196: throw new JsonbException(Messages.getMessage(MessageKeys.MULTIPLE_JSONB_CREATORS, clazz));
197: }
198:
199: final Parameter[] parameters = executable.getParameters();
200:
201: CreatorModel[] creatorModels = new CreatorModel[parameters.length];
202:• for (int i = 0; i < parameters.length; i++) {
203: final Parameter parameter = parameters[i];
204: final JsonbProperty jsonbPropertyAnnotation = parameter.getAnnotation(JsonbProperty.class);
205:• if (jsonbPropertyAnnotation != null && !jsonbPropertyAnnotation.value().isEmpty()) {
206: creatorModels[i] = new CreatorModel(jsonbPropertyAnnotation.value(), parameter, executable, jsonbContext);
207: } else {
208: creatorModels[i] = new CreatorModel(parameter.getName(), parameter, executable, jsonbContext);
209: }
210: }
211:
212: return new JsonbCreator(executable, creatorModels);
213: }
214:
215: /**
216: * Checks for {@link JsonbAdapter} on a property.
217: *
218: * @param property property not null
219: * @return components info
220: */
221: public AdapterBinding getAdapterBinding(Property property) {
222: Objects.requireNonNull(property);
223: JsonbTypeAdapter adapterAnnotation = getAnnotationFromProperty(JsonbTypeAdapter.class, property)
224: .orElseGet(() -> getAnnotationFromPropertyType(property, JsonbTypeAdapter.class));
225:• if (adapterAnnotation == null) {
226: return null;
227: }
228:
229: return getAdapterBindingFromAnnotation(adapterAnnotation, ReflectionUtils.getOptionalRawType(property.getPropertyType()));
230: }
231:
232: /**
233: * Checks for {@link JsonbAdapter} on a type.
234: *
235: * @param clsElement type not null
236: * @return components info
237: */
238: public AdapterBinding getAdapterBinding(JsonbAnnotatedElement<Class<?>> clsElement) {
239: Objects.requireNonNull(clsElement);
240:
241: JsonbTypeAdapter adapterAnnotation = clsElement.getElement().getAnnotation(JsonbTypeAdapter.class);
242:• if (adapterAnnotation == null) {
243: return null;
244: }
245:
246: return getAdapterBindingFromAnnotation(adapterAnnotation, Optional.ofNullable(clsElement.getElement()));
247: }
248:
249: private AdapterBinding getAdapterBindingFromAnnotation(JsonbTypeAdapter adapterAnnotation, Optional<Class<?>> expectedClass) {
250: final Class<? extends JsonbAdapter> adapterClass = adapterAnnotation.value();
251: final AdapterBinding adapterBinding = jsonbContext.getComponentMatcher().introspectAdapterBinding(adapterClass, null);
252:
253:• if (expectedClass.isPresent() && !(
254:• ReflectionUtils.getRawType(adapterBinding.getBindingType()).isAssignableFrom(expectedClass.get()))) {
255: throw new JsonbException(Messages.getMessage(MessageKeys.ADAPTER_INCOMPATIBLE,
256: adapterBinding.getBindingType(),
257: expectedClass.get()));
258: }
259: return adapterBinding;
260: }
261:
262: /**
263: * Checks for {@link JsonbDeserializer} on a property.
264: *
265: * @param property property not null
266: * @return components info
267: */
268: public DeserializerBinding getDeserializerBinding(Property property) {
269: Objects.requireNonNull(property);
270: JsonbTypeDeserializer deserializerAnnotation = getAnnotationFromProperty(JsonbTypeDeserializer.class, property)
271: .orElseGet(() -> getAnnotationFromPropertyType(property, JsonbTypeDeserializer.class));
272:• if (deserializerAnnotation == null) {
273: return null;
274: }
275:
276: final Class<? extends JsonbDeserializer> deserializerClass = deserializerAnnotation.value();
277: return jsonbContext.getComponentMatcher().introspectDeserializerBinding(deserializerClass, null);
278: }
279:
280: /**
281: * Checks for {@link JsonbDeserializer} on a {@link Parameter}.
282: *
283: * @param parameter parameter not null
284: * @return components info
285: */
286: public DeserializerBinding<?> getDeserializerBinding(Parameter parameter) {
287: Objects.requireNonNull(parameter);
288: JsonbTypeDeserializer deserializerAnnotation =
289: Optional.ofNullable(parameter.getDeclaredAnnotation(JsonbTypeDeserializer.class))
290: .orElseGet(() -> getAnnotationFromParameterType(parameter, JsonbTypeDeserializer.class));
291:• if (deserializerAnnotation == null) {
292: return null;
293: }
294:
295: final Class<? extends JsonbDeserializer> deserializerClass = deserializerAnnotation.value();
296: return jsonbContext.getComponentMatcher().introspectDeserializerBinding(deserializerClass, null);
297: }
298:
299: /**
300: * Checks for {@link JsonbAdapter} on a {@link Parameter}.
301: *
302: * @param parameter parameter not null
303: * @return components info
304: */
305: public AdapterBinding getAdapterBinding(Parameter parameter) {
306: Objects.requireNonNull(parameter);
307: JsonbTypeAdapter adapter =
308: Optional.ofNullable(parameter.getDeclaredAnnotation(JsonbTypeAdapter.class))
309: .orElseGet(() -> getAnnotationFromParameterType(parameter, JsonbTypeAdapter.class));
310:• if (adapter == null) {
311: return null;
312: }
313:
314: return getAdapterBindingFromAnnotation(adapter, ReflectionUtils.getOptionalRawType(parameter.getParameterizedType()));
315: }
316:
317: private <T extends Annotation> T getAnnotationFromParameterType(Parameter parameter, Class<T> annotationClass) {
318: final Optional<Class<?>> optionalRawType = ReflectionUtils.getOptionalRawType(parameter.getParameterizedType());
319: //will not work for type variable properties, which are bound to class that is annotated.
320: return optionalRawType.map(aClass -> findAnnotation(collectAnnotations(aClass).getAnnotations(), annotationClass))
321: .orElse(null);
322: }
323:
324: /**
325: * Checks for {@link JsonbDeserializer} on a type.
326: *
327: * @param clsElement type not null
328: * @return components info
329: */
330: public DeserializerBinding getDeserializerBinding(JsonbAnnotatedElement<Class<?>> clsElement) {
331: Objects.requireNonNull(clsElement);
332: JsonbTypeDeserializer deserializerAnnotation = clsElement.getElement().getAnnotation(JsonbTypeDeserializer.class);
333:• if (deserializerAnnotation == null) {
334: return null;
335: }
336:
337: final Class<? extends JsonbDeserializer> deserializerClass = deserializerAnnotation.value();
338: return jsonbContext.getComponentMatcher().introspectDeserializerBinding(deserializerClass, null);
339: }
340:
341: /**
342: * Checks for {@link JsonbSerializer} on a property.
343: *
344: * @param property property not null
345: * @return components info
346: */
347: public SerializerBinding getSerializerBinding(Property property) {
348: Objects.requireNonNull(property);
349: JsonbTypeSerializer serializerAnnotation = getAnnotationFromProperty(JsonbTypeSerializer.class, property)
350: .orElseGet(() -> getAnnotationFromPropertyType(property, JsonbTypeSerializer.class));
351:• if (serializerAnnotation == null) {
352: return null;
353: }
354:
355: final Class<? extends JsonbSerializer> serializerClass = serializerAnnotation.value();
356: return jsonbContext.getComponentMatcher().introspectSerializerBinding(serializerClass, null);
357:
358: }
359:
360: /**
361: * Checks for {@link JsonbSerializer} on a type.
362: *
363: * @param clsElement type not null
364: * @return components info
365: */
366: public SerializerBinding getSerializerBinding(JsonbAnnotatedElement<Class<?>> clsElement) {
367: Objects.requireNonNull(clsElement);
368: JsonbTypeSerializer serializerAnnotation = clsElement.getElement().getAnnotation(JsonbTypeSerializer.class);
369:• if (serializerAnnotation == null) {
370: return null;
371: }
372:
373: final Class<? extends JsonbSerializer> serializerClass = serializerAnnotation.value();
374: return jsonbContext.getComponentMatcher().introspectSerializerBinding(serializerClass, null);
375: }
376:
377: private <T extends Annotation> T getAnnotationFromPropertyType(Property property, Class<T> annotationClass) {
378: final Optional<Class<?>> optionalRawType = ReflectionUtils.getOptionalRawType(property.getPropertyType());
379:• if (!optionalRawType.isPresent()) {
380: //will not work for type variable properties, which are bound to class that is annotated.
381: return null;
382: }
383: return findAnnotation(collectAnnotations(optionalRawType.get()).getAnnotations(), annotationClass);
384: }
385:
386: /**
387: * Checks if property is nillable.
388: * Looks for {@link JsonbProperty} nillable attribute only.
389: * JsonbNillable is checked only for ClassModels.
390: *
391: * @param property property to search in, not null
392: * @return True if property should be serialized when null.
393: */
394: public Optional<Boolean> isPropertyNillable(Property property) {
395: Objects.requireNonNull(property);
396:
397: Optional<JsonbNillable> nillable = getAnnotationFromProperty(JsonbNillable.class, property);
398:• if (nillable.isPresent()) {
399: return nillable.map(JsonbNillable::value);
400: }
401: final Optional<JsonbProperty> jsonbProperty = getAnnotationFromProperty(JsonbProperty.class, property);
402: return jsonbProperty.map(JsonbProperty::nillable);
403:
404: }
405:
406: /**
407: * Checks for JsonbNillable annotation on a class, its superclasses and interfaces.
408: *
409: * @param clazzElement class to search JsonbNillable in.
410: * @return true if found
411: */
412: public boolean isClassNillable(JsonbAnnotatedElement<Class<?>> clazzElement) {
413: final JsonbNillable jsonbNillable = findAnnotation(clazzElement.getAnnotations(), JsonbNillable.class);
414:• if (jsonbNillable != null) {
415: return jsonbNillable.value();
416: }
417: Class<?> clazz = clazzElement.getElement();
418:• if (clazz == Optional.class
419: || clazz == OptionalDouble.class
420: || clazz == OptionalInt.class
421: || clazz == OptionalLong.class) {
422: return true;
423: }
424: return jsonbContext.getConfigProperties().getConfigNullable();
425: }
426:
427: /**
428: * Checks for {@link JsonbPropertyOrder} annotation.
429: *
430: * @param clazzElement class to search on
431: * @return ordered properties names or null if not found
432: */
433: public String[] getPropertyOrder(JsonbAnnotatedElement<Class<?>> clazzElement) {
434: final JsonbPropertyOrder jsonbPropertyOrder = clazzElement.getElement().getAnnotation(JsonbPropertyOrder.class);
435:• return jsonbPropertyOrder != null ? jsonbPropertyOrder.value() : null;
436: }
437:
438: /**
439: * Checks if property is annotated transient. If JsonbTransient annotation is present on field getter or setter, and other
440: * annotation is present
441: * on either of it, JsonbException is thrown with message describing collision.
442: *
443: * @param property The property to inspect if there is any {@link JsonbTransient} annotation defined for it
444: * @return Set of {@link AnnotationTarget}s specifying in which scope the {@link JsonbTransient} is applied
445: */
446: public EnumSet<AnnotationTarget> getJsonbTransientCategorized(Property property) {
447: Objects.requireNonNull(property);
448: EnumSet<AnnotationTarget> transientTarget = EnumSet.noneOf(AnnotationTarget.class);
449: Map<AnnotationTarget, JsonbTransient> annotationFromPropertyCategorized = getAnnotationFromPropertyCategorized(
450: JsonbTransient.class,
451: property);
452:• if (annotationFromPropertyCategorized.size() > 0) {
453: transientTarget.addAll(annotationFromPropertyCategorized.keySet());
454: return transientTarget;
455: }
456:
457: return transientTarget;
458: }
459:
460: /**
461: * Search {@link JsonbDateFormat} on property, if not found looks at annotations declared on property type class.
462: *
463: * @param property Property to search on.
464: * @return Map of {@link JsonbDateFormatter} instances categorized by their scopes (class, property, getter or setter). If
465: * there is no date
466: * formatter specified for given property, an empty map would be returned
467: */
468: public Map<AnnotationTarget, JsonbDateFormatter> getJsonbDateFormatCategorized(Property property) {
469: Objects.requireNonNull(property);
470:
471: Map<AnnotationTarget, JsonbDateFormatter> result = new HashMap<>();
472: Map<AnnotationTarget, JsonbDateFormat> annotationFromPropertyCategorized = getAnnotationFromPropertyCategorized(
473: JsonbDateFormat.class,
474: property);
475:• if (annotationFromPropertyCategorized.size() != 0) {
476: annotationFromPropertyCategorized.forEach((key, annotation) -> result
477: .put(key, createJsonbDateFormatter(annotation.value(), annotation.locale(), property)));
478: }
479:
480: // No date format on property, try class level
481: // if property is not TypeVariable and its class is not date skip it
482: final Optional<Class<?>> propertyRawTypeOptional = ReflectionUtils.getOptionalRawType(property.getPropertyType());
483:• if (propertyRawTypeOptional.isPresent()) {
484: Class<?> rawType = propertyRawTypeOptional.get();
485: if (!(
486:• Date.class.isAssignableFrom(rawType) || Calendar.class.isAssignableFrom(rawType)
487:• || TemporalAccessor.class.isAssignableFrom(rawType))) {
488: return new HashMap<>();
489: }
490: }
491:
492: JsonbDateFormat classLevelDateFormatter = findAnnotation(property.getDeclaringClassElement().getAnnotations(),
493: JsonbDateFormat.class);
494:• if (classLevelDateFormatter != null) {
495: result.put(AnnotationTarget.CLASS,
496: createJsonbDateFormatter(classLevelDateFormatter.value(), classLevelDateFormatter.locale(), property));
497: }
498:
499: return result;
500: }
501:
502: /**
503: * Search for {@link JsonbDateFormat} annotation on java class and construct {@link JsonbDateFormatter}.
504: * If not found looks at annotations declared on property type class.
505: *
506: * @param clazzElement class to search not null
507: * @return formatter to use
508: */
509: public JsonbDateFormatter getJsonbDateFormat(JsonbAnnotatedElement<Class<?>> clazzElement) {
510: Objects.requireNonNull(clazzElement);
511: final JsonbDateFormat format = findAnnotation(clazzElement.getAnnotations(), JsonbDateFormat.class);
512:• if (format == null) {
513: return jsonbContext.getConfigProperties().getConfigDateFormatter();
514: }
515: return new JsonbDateFormatter(format.value(), format.locale());
516: }
517:
518: /**
519: * Search for {@link JsonbNumberFormat} annotation on java class.
520: *
521: * @param clazzElement class to search not null
522: * @return formatter to use
523: */
524: public JsonbNumberFormatter getJsonbNumberFormat(JsonbAnnotatedElement<Class<?>> clazzElement) {
525: final JsonbNumberFormat formatAnnotation = findAnnotation(clazzElement.getAnnotations(), JsonbNumberFormat.class);
526:• if (formatAnnotation == null) {
527: return null;
528: }
529: return new JsonbNumberFormatter(formatAnnotation.value(), formatAnnotation.locale());
530: }
531:
532: /**
533: * Search {@link JsonbNumberFormat} on property, if not found looks at annotations declared on property type class.
534: *
535: * @param property Property to search on.
536: * @return Map of {@link JsonbNumberFormatter} instances categorized by their scopes (class, property, getter or setter).
537: * If there is no number
538: * formatter specified for given property, an empty map would be returned
539: */
540: public Map<AnnotationTarget, JsonbNumberFormatter> getJsonNumberFormatter(Property property) {
541: Map<AnnotationTarget, JsonbNumberFormatter> result = new HashMap<>();
542: Map<AnnotationTarget, JsonbNumberFormat> annotationFromPropertyCategorized = getAnnotationFromPropertyCategorized(
543: JsonbNumberFormat.class,
544: property);
545: // if (annotationFromPropertyCategorized.size() == 0) {
546: // final Optional<Class<?>> propertyRawTypeOptional = ReflectionUtils.getOptionalRawType(property
547: // .getPropertyType());
548: // if (propertyRawTypeOptional.isPresent()) {
549: // Class<?> rawType = propertyRawTypeOptional.get();
550: // if (!Number.class.isAssignableFrom(rawType)) {
551: // return new HashMap<>();
552: // }
553: // }
554: // } else {
555: // annotationFromPropertyCategorized.forEach((key, annotation) -> result
556: // .put(key, new JsonbNumberFormatter(annotation.value(), annotation.locale())));
557: // }
558: annotationFromPropertyCategorized.forEach((key, annotation) -> result
559: .put(key, new JsonbNumberFormatter(annotation.value(), annotation.locale())));
560:
561: JsonbNumberFormat classLevelNumberFormatter = findAnnotation(property.getDeclaringClassElement().getAnnotations(),
562: JsonbNumberFormat.class);
563:• if (classLevelNumberFormatter != null) {
564: result.put(AnnotationTarget.CLASS,
565: new JsonbNumberFormatter(classLevelNumberFormatter.value(), classLevelNumberFormatter.locale()));
566: }
567:
568: return result;
569: }
570:
571: /**
572: * Returns {@link JsonbNumberFormatter} instance if {@link JsonbNumberFormat} annotation is present.
573: *
574: * @param param annotated method parameter
575: * @return formatter instance if {@link JsonbNumberFormat} is present otherwise null
576: */
577: public JsonbNumberFormatter getConstructorNumberFormatter(JsonbAnnotatedElement<Parameter> param) {
578: return param.getAnnotation(JsonbNumberFormat.class)
579: .map(annotation -> new JsonbNumberFormatter(annotation.value(), annotation.locale()))
580: .orElse(null);
581: }
582:
583: /**
584: * Returns {@link JsonbDateFormatter} instance if {@link JsonbDateFormat} annotation is present.
585: *
586: * @param param annotated method parameter
587: * @return formatter instance if {@link JsonbDateFormat} is present otherwise null
588: */
589: public JsonbDateFormatter getConstructorDateFormatter(JsonbAnnotatedElement<Parameter> param) {
590: return param.getAnnotation(JsonbDateFormat.class)
591: .map(annotation -> new JsonbDateFormatter(DateTimeFormatter.ofPattern(annotation.value(),
592: Locale.forLanguageTag(annotation.locale())),
593: annotation.value(), annotation.locale()))
594: .orElse(null);
595: }
596:
597: /**
598: * Creates {@link JsonbDateFormatter} caches formatter instance if possible.
599: * For DEFAULT_FORMAT appropriate singleton instances from java.time.format.DateTimeFormatter
600: * are used in date converters.
601: */
602: private JsonbDateFormatter createJsonbDateFormatter(String format, String locale, Property property) {
603:• if (JsonbDateFormat.TIME_IN_MILLIS.equals(format) || JsonbDateFormat.DEFAULT_FORMAT.equals(format)) {
604: //for epochMillis formatter is not used, for default format singleton instances of DateTimeFormatter
605: //are used in the converters
606: return new JsonbDateFormatter(format, locale);
607: }
608:
609: final Optional<Class<?>> optionalRawType = ReflectionUtils.getOptionalRawType(property.getPropertyType());
610: final Class<?> propertyRawType = optionalRawType.orElse(null);
611:
612:• if (propertyRawType != null
613:• && !TemporalAccessor.class.isAssignableFrom(propertyRawType)
614:• && !Date.class.isAssignableFrom(propertyRawType)
615:• && !Calendar.class.isAssignableFrom(propertyRawType)) {
616: throw new IllegalStateException(Messages.getMessage(MessageKeys.UNSUPPORTED_DATE_TYPE, propertyRawType));
617: }
618:
619: DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder();
620: builder.appendPattern(format);
621:• if (jsonbContext.getConfigProperties().isZeroTimeDefaulting()) {
622: builder.parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0);
623: builder.parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0);
624: builder.parseDefaulting(ChronoField.HOUR_OF_DAY, 0);
625: }
626: DateTimeFormatter dateTimeFormatter = builder.toFormatter(Locale.forLanguageTag(locale));
627: return new JsonbDateFormatter(dateTimeFormatter, format, locale);
628: }
629:
630: /**
631: * Get a @JsonbVisibility annotation from a class or its package.
632: *
633: * @param clazz Class to lookup annotation
634: * @return Instantiated PropertyVisibilityStrategy if annotation is present
635: */
636: public PropertyVisibilityStrategy getPropertyVisibilityStrategy(Class<?> clazz) {
637: JsonbVisibility visibilityAnnotation = findAnnotation(clazz.getDeclaredAnnotations(), JsonbVisibility.class);
638:• if ((visibilityAnnotation == null) && (clazz.getPackage() != null)) {
639: visibilityAnnotation = findAnnotation(clazz.getPackage().getDeclaredAnnotations(), JsonbVisibility.class);
640: }
641:• if (visibilityAnnotation != null) {
642: return ReflectionUtils.createNoArgConstructorInstance(
643: ReflectionUtils.getDefaultConstructor(visibilityAnnotation.value(), true));
644: }
645: return jsonbContext.getConfigProperties().getPropertyVisibilityStrategy();
646: }
647:
648: /**
649: * Gets an annotation from first resolved annotation in a property in this order:
650: * <p>1. Field, 2. Getter, 3 Setter.</p>
651: * First found overrides other.
652: *
653: * @param annotationClass Annotation class to search for
654: * @param property property to search in
655: * @param <T> Annotation type
656: * @return Annotation if found, null otherwise
657: */
658: private <T extends Annotation> Optional<T> getAnnotationFromProperty(Class<T> annotationClass, Property property) {
659: T fieldAnnotation = getFieldAnnotation(annotationClass, property.getFieldElement());
660:• if (fieldAnnotation != null) {
661: return Optional.of(fieldAnnotation);
662: }
663:
664: T getterAnnotation = getMethodAnnotation(annotationClass, property.getGetterElement());
665:• if (getterAnnotation != null) {
666: return Optional.of(getterAnnotation);
667: }
668:
669: T setterAnnotation = getMethodAnnotation(annotationClass, property.getSetterElement());
670:• if (setterAnnotation != null) {
671: return Optional.of(setterAnnotation);
672: }
673:
674: return Optional.empty();
675: }
676:
677: /**
678: * An override of {@link #getAnnotationFromProperty(Class, Property)} in which it returns the results as a map so that the
679: * caller can decide which
680: * one to be used for read/write operation. Some annotations should have different behaviours based on the scope that
681: * they're applied on.
682: *
683: * @param annotationClass The annotation class to search
684: * @param property The property to search in
685: * @param <T> Annotation type
686: * @return A map of all occurrences of requested annotation for given property. Caller can determine based on
687: * {@link AnnotationTarget} that given
688: * annotation is specified on what level (Class, Property, Getter or Setter). If no annotation found for given property, an
689: * empty map would be
690: * returned
691: */
692: private <T extends Annotation> Map<AnnotationTarget, T> getAnnotationFromPropertyCategorized(Class<T> annotationClass,
693: Property property) {
694: Map<AnnotationTarget, T> result = new HashMap<>();
695: T fieldAnnotation = getFieldAnnotation(annotationClass, property.getFieldElement());
696:• if (fieldAnnotation != null) {
697: result.put(AnnotationTarget.PROPERTY, fieldAnnotation);
698: }
699:
700: T getterAnnotation = getMethodAnnotation(annotationClass, property.getGetterElement());
701:• if (getterAnnotation != null) {
702: result.put(AnnotationTarget.GETTER, getterAnnotation);
703: }
704:
705: T setterAnnotation = getMethodAnnotation(annotationClass, property.getSetterElement());
706:• if (setterAnnotation != null) {
707: result.put(AnnotationTarget.SETTER, setterAnnotation);
708: }
709:
710: return result;
711: }
712:
713: private <T extends Annotation> T getFieldAnnotation(Class<T> annotationClass, JsonbAnnotatedElement<Field> fieldElement) {
714:• if (fieldElement == null) {
715: return null;
716: }
717: return findAnnotation(fieldElement.getAnnotations(), annotationClass);
718: }
719:
720: private <T extends Annotation> T findAnnotation(Annotation[] declaredAnnotations, Class<T> annotationClass) {
721: return AnnotationFinder.findAnnotation(declaredAnnotations, annotationClass, new HashSet<>());
722: }
723:
724: /**
725: * Finds annotations incompatible with {@link JsonbTransient} annotation.
726: *
727: * @param target target to check
728: */
729: public void checkTransientIncompatible(JsonbAnnotatedElement<?> target) {
730:• if (target == null) {
731: return;
732: }
733:
734:• for (Class<? extends Annotation> ann : TRANSIENT_INCOMPATIBLE) {
735: Annotation annotation = findAnnotation(target.getAnnotations(), ann);
736:• if (annotation != null) {
737: throw new JsonbException(Messages.getMessage(MessageKeys.JSONB_TRANSIENT_WITH_OTHER_ANNOTATIONS));
738: }
739: }
740: }
741:
742: private <T extends Annotation> T getMethodAnnotation(Class<T> annotationClass, JsonbAnnotatedElement<Method> methodElement) {
743:• if (methodElement == null) {
744: return null;
745: }
746: return findAnnotation(methodElement.getAnnotations(), annotationClass);
747: }
748:
749: private <T extends Annotation> void collectFromInterfaces(Class<T> annotationClass,
750: Class<?> clazz,
751: Map<Class<?>, T> collectedAnnotations) {
752:
753:• for (Class<?> interfaceClass : clazz.getInterfaces()) {
754: T annotation = findAnnotation(interfaceClass.getDeclaredAnnotations(), annotationClass);
755:• if (annotation != null) {
756: collectedAnnotations.put(interfaceClass, annotation);
757: }
758: collectFromInterfaces(annotationClass, interfaceClass, collectedAnnotations);
759: }
760: }
761:
762: /**
763: * Get class interfaces recursively.
764: *
765: * @param cls Class to process.
766: * @return A list of all class interfaces.
767: */
768: public Set<Class<?>> collectInterfaces(Class<?> cls) {
769: Set<Class<?>> collected = new LinkedHashSet<>();
770: Queue<Class<?>> toScan = new LinkedList<>(Arrays.asList(cls.getInterfaces()));
771: Class<?> nextIfc;
772:• while ((nextIfc = toScan.poll()) != null) {
773: collected.add(nextIfc);
774: toScan.addAll(Arrays.asList(nextIfc.getInterfaces()));
775: }
776: return collected;
777: }
778:
779: /**
780: * Processes customizations.
781: *
782: * @param clsElement Element to process.
783: * @return Populated {@link ClassCustomization} instance.
784: */
785: public ClassCustomization introspectCustomization(JsonbAnnotatedElement<Class<?>> clsElement,
786: ClassCustomization parentCustomization) {
787: return ClassCustomization.builder()
788: .nillable(isClassNillable(clsElement))
789: .dateTimeFormatter(getJsonbDateFormat(clsElement))
790: .numberFormatter(getJsonbNumberFormat(clsElement))
791: .creator(getCreator(clsElement.getElement()))
792: .propertyOrder(getPropertyOrder(clsElement))
793: .adapterBinding(getAdapterBinding(clsElement))
794: .serializerBinding(getSerializerBinding(clsElement))
795: .deserializerBinding(getDeserializerBinding(clsElement))
796: .propertyVisibilityStrategy(getPropertyVisibilityStrategy(clsElement.getElement()))
797: .polymorphismConfig(getPolymorphismConfig(clsElement, parentCustomization))
798: .build();
799: }
800:
801: private TypeInheritanceConfiguration getPolymorphismConfig(JsonbAnnotatedElement<Class<?>> clsElement,
802: ClassCustomization parentCustomization) {
803: TypeInheritanceConfiguration parentPolyConfig = parentCustomization.getPolymorphismConfig();
804:
805: LinkedList<AnnotationWrapper<?>> annotations = clsElement.getAnnotations(JsonbTypeInfo.class);
806:
807:• if (parentPolyConfig != null) {
808:• if (annotations.size() == 1 && annotations.getFirst().isInherited()) {
809: throw new JsonbException("CHANGE");
810:• } else if (annotations.size() > 1) {
811: throw new JsonbException("CHANGE");
812:• } else if (annotations.isEmpty()) {
813: return TypeInheritanceConfiguration.builder().of(parentPolyConfig)
814: .inherited(true)
815: .build();
816: }
817: }
818: ListIterator<AnnotationWrapper<?>> listIterator = annotations.listIterator(annotations.size());
819:• while (listIterator.hasPrevious()) {
820: AnnotationWrapper<?> annotationWrapper = listIterator.previous();
821: JsonbTypeInfo annotation = (JsonbTypeInfo) annotationWrapper.getAnnotation();
822: TypeInheritanceConfiguration.Builder builder = TypeInheritanceConfiguration.builder();
823: builder.fieldName(annotation.key())
824: .inherited(annotationWrapper.isInherited())
825: .parentConfig(parentPolyConfig)
826: .definedType(annotationWrapper.getDefinedType());
827:• for (JsonbSubtype subType : annotation.value()) {
828:• if (!annotationWrapper.getDefinedType().isAssignableFrom(subType.type())) {
829: throw new JsonbException("Defined alias type has to be child of the current type. JsonbSubType on the "
830: + annotationWrapper.getDefinedType().getName()
831: + " defines incorrect alias "
832: + subType);
833: }
834: builder.alias(subType.type(), subType.alias());
835: }
836: parentPolyConfig = builder.build();
837: }
838:
839: checkDuplicityPolymorphicPropertyNames(parentPolyConfig);
840:
841: return parentPolyConfig;
842: }
843:
844: private void checkDuplicityPolymorphicPropertyNames(TypeInheritanceConfiguration typeInheritanceConfiguration) {
845:• if (typeInheritanceConfiguration == null) {
846: return;
847: }
848: Map<String, TypeInheritanceConfiguration> keyNames = new HashMap<>();
849: TypeInheritanceConfiguration current = typeInheritanceConfiguration;
850:• while (current != null) {
851: String fieldName = current.getFieldName();
852:• if (keyNames.containsKey(fieldName)) {
853: TypeInheritanceConfiguration conflicting = keyNames.get(fieldName);
854: throw new JsonbException("One polymorphic chain cannot have two conflicting property names. "
855: + "Polymorphic type defined on the type "
856: + conflicting.getDefinedType().getName() + " and "
857: + current.getDefinedType().getName() + " have conflicting property name");
858: }
859: keyNames.put(fieldName, current);
860: current = current.getParentConfig();
861: }
862: }
863:
864: /**
865: * Returns class if {@link ImplementationClass} annotation is present.
866: *
867: * @param property annotated property
868: * @return Class if {@link ImplementationClass} is present otherwise null
869: */
870: public Class<?> getImplementationClass(Property property) {
871: Optional<ImplementationClass> annotationFromProperty = getAnnotationFromProperty(ImplementationClass.class, property);
872: return annotationFromProperty.<Class<?>>map(ImplementationClass::value).orElse(null);
873: }
874:
875: /**
876: * Collect annotations of given class, its interfaces and the package.
877: *
878: * @param clazz Class to process.
879: * @return Element with class and annotations.
880: */
881: public JsonbAnnotatedElement<Class<?>> collectAnnotations(Class<?> clazz) {
882: JsonbAnnotatedElement<Class<?>> classElement = new JsonbAnnotatedElement<>(clazz);
883:
884:• if (BuiltInTypes.isKnownType(clazz)) {
885: return classElement;
886: }
887:
888: Map<Class<? extends Annotation>, LinkedList<AnnotationWrapper<?>>> interfaceAnnotations
889: = collectInterfaceAnnotations(clazz, clazz);
890:• for (LinkedList<AnnotationWrapper<?>> wrappers : interfaceAnnotations.values()) {
891:• for (AnnotationWrapper<?> wrapper : wrappers) {
892:• if (classElement.getAnnotation(wrapper.getAnnotation().annotationType()).isEmpty()
893:• || REPEATABLE.contains(wrapper.getAnnotation().annotationType())) {
894: classElement.putAnnotationWrapper(wrapper);
895: }
896: }
897: }
898:
899:• if (!clazz.isPrimitive() && !clazz.isArray() && (clazz.getPackage() != null)) {
900: addIfNotPresent(classElement, null, clazz.getPackage().getAnnotations());
901: }
902: return classElement;
903: }
904:
905: private Map<Class<? extends Annotation>, LinkedList<AnnotationWrapper<?>>> collectInterfaceAnnotations(Class<?> currentInterf,
906: Class<?> processed) {
907: Map<Class<? extends Annotation>, LinkedList<AnnotationWrapper<?>>> map = new HashMap<>();
908:• if (!currentInterf.equals(processed)) {
909:• for (Annotation annotation : currentInterf.getDeclaredAnnotations()) {
910: map.computeIfAbsent(annotation.annotationType(), aClass -> new LinkedList<>())
911: .add(new AnnotationWrapper<>(annotation, true, currentInterf));
912: }
913: }
914:
915: Map<Class<? extends Annotation>, LinkedList<AnnotationWrapper<?>>> parents = new HashMap<>();
916:• for (Class<?> parentInterf : currentInterf.getInterfaces()) {
917: Map<Class<? extends Annotation>, LinkedList<AnnotationWrapper<?>>> current = collectInterfaceAnnotations(parentInterf,
918: processed);
919: current.entrySet().stream()
920:• .filter(entry -> !parents.containsKey(entry.getKey()) || REPEATABLE.contains(entry.getKey()))
921: .peek(entry -> {
922:• if (parents.containsKey(entry.getKey())) {
923: throw new JsonbException("CHANGE THIS EXCEPTION");
924: }
925: })
926: .forEach(entry -> {
927: parents.computeIfAbsent(entry.getKey(), aClass -> new LinkedList<>()).addAll(entry.getValue());
928: map.computeIfAbsent(entry.getKey(), aClass -> new LinkedList<>()).addAll(entry.getValue());
929: });
930: }
931: return map;
932: }
933:
934: // private void collectParentInterfaceAnnotations(Class<?> currentInterf,
935: // Map<Class<? extends Annotation>, LinkedList<Annotation>> overall) {
936: // Map<Class<? extends Annotation>, LinkedList<Annotation>> parents = new HashMap<>();
937: // for (Class<?> parentInterf : currentInterf.getInterfaces()) {
938: // collectParentInterfaceAnnotations(parentInterf, );
939: // current.entrySet().stream()
940: // .filter(entry -> parents.containsKey(entry.getKey()) || REPEATABLE.contains(entry.getKey()))
941: // .peek(entry -> {
942: // if (parents.containsKey(entry.getKey())) {
943: // throw new JsonbException("CHANGE THIS EXCEPTION");
944: // }
945: // })
946: // .forEach(entry -> {
947: // parents.computeIfAbsent(entry.getKey(), aClass -> new LinkedList<>()).addAll(entry.getValue());
948: // map.computeIfAbsent(entry.getKey(), aClass -> new LinkedList<>()).addAll(entry.getValue());
949: // });
950: // }
951: // if (currentInterf.isInterface()) {
952: // for (Annotation annotation : currentInterf.getDeclaredAnnotations()) {
953: // map.computeIfAbsent(annotation.annotationType(), aClass -> new LinkedList<>()).add(annotation);
954: // }
955: // }
956: // return map;
957: // }
958:
959: private void addIfNotPresent(JsonbAnnotatedElement<?> element, Class<?> definedType, Annotation... annotations) {
960:• for (Annotation annotation : annotations) {
961:• if (element.getAnnotation(annotation.annotationType()).isEmpty()
962:• || REPEATABLE.contains(annotation.annotationType())) {
963: element.putAnnotation(annotation, true, definedType);
964: }
965: }
966: }
967:
968: public boolean requiredParameters(Executable executable, JsonbAnnotatedElement<Parameter> annotated) {
969: return jsonbContext.getConfigProperties().hasRequiredCreatorParameters();
970: // if (OPTIONALS.contains(annotated.getElement().getType())) {
971: // return false;
972: // }
973: // return annotated.getAnnotation(JsonbRequired.class)
974: // .or(() -> Optional.ofNullable(executable.getAnnotation(JsonbRequired.class)))
975: // .map(JsonbRequired::value)
976: // .orElseGet(() -> jsonbContext.getConfigProperties().hasRequiredCreatorParameters());
977: }
978: }