-
Notifications
You must be signed in to change notification settings - Fork 94
/
ClassModel.java
187 lines (164 loc) · 6.29 KB
/
ClassModel.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
/*******************************************************************************
* Copyright (c) 2015, 2018 Oracle and/or its affiliates. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
* <p>
* Contributors:
* Dmitry Kornilov - initial implementation
******************************************************************************/
package org.eclipse.yasson.internal.model;
import org.eclipse.yasson.internal.ReflectionUtils;
import org.eclipse.yasson.internal.model.customization.StrategiesProvider;
import org.eclipse.yasson.internal.model.customization.ClassCustomization;
import javax.json.bind.config.PropertyNamingStrategy;
import java.lang.reflect.Constructor;
import java.util.*;
import java.util.stream.Collectors;
/**
* A model for Java class.
*
* @author Dmitry Kornilov
*/
public class ClassModel {
private final Class<?> clazz;
private final ClassCustomization classCustomization;
private final ClassModel parentClassModel;
private final Constructor<?> defaultConstructor;
/**
* A map of all class properties, including properties from superclasses. Used to access by name.
*/
private Map<String, PropertyModel> properties;
/**
* Sorted properties according to sorting strategy. Used for serialization property ordering.
*/
private PropertyModel[] sortedProperties;
private final PropertyNamingStrategy propertyNamingStrategy;
/**
* Gets a property model by default (non customized) name.
*
* @param name A name as parsed from field / getter / setter without annotation customizing.
* @return Property model.
*/
public PropertyModel getPropertyModel(String name) {
return properties.get(name);
}
/**
* Create instance of class model.
*
* @param clazz Class to model.
* @param customization Customization of the class parsed from annotations.
* @param parentClassModel Class model of parent class.
* @param propertyNamingStrategy Property naming strategy.
*/
public ClassModel(Class<?> clazz, ClassCustomization customization, ClassModel parentClassModel, PropertyNamingStrategy propertyNamingStrategy) {
this.clazz = clazz;
this.classCustomization = customization;
this.parentClassModel = parentClassModel;
this.propertyNamingStrategy = propertyNamingStrategy;
this.defaultConstructor = ReflectionUtils.getDefaultConstructor(clazz, false);
setProperties(new ArrayList<>());
}
/**
* Search for field in this class model and superclasses of its class.
*
* @param jsonReadName name as it appears in JSON during reading.
* @return PropertyModel if found.
*/
public PropertyModel findPropertyModelByJsonReadName(String jsonReadName) {
Objects.requireNonNull(jsonReadName);
return searchProperty(this, jsonReadName);
}
private PropertyModel searchProperty(ClassModel classModel, String jsonReadName) {
//Standard javabean properties without overridden name (most of the cases)
final PropertyModel result = classModel.getPropertyModel(jsonReadName);
if (result != null && result.getPropertyName().equals(result.getReadName())) {
return result;
}
//Search for overridden name on setter with @JsonbProperty annotation
for (PropertyModel propertyModel : properties.values()) {
if (equalsReadName(jsonReadName, propertyModel)) {
return propertyModel;
}
}
//property not found
return null;
}
/**
* Check if name is equal according to property strategy. In case of {@link CaseInsensitiveStrategy} ignore case.
* User can provide own strategy implementation, cast to custom interface is not an option.
*
* @return True if names are equal.
*/
private boolean equalsReadName(String jsonName, PropertyModel propertyModel) {
final String propertyReadName = propertyModel.getReadName();
if (propertyNamingStrategy == StrategiesProvider.CASE_INSENSITIVE_STRATEGY) {
return jsonName.equalsIgnoreCase(propertyReadName);
}
return jsonName.equals(propertyReadName);
}
/**
* Gets customization.
*
* @return Customization.
*/
public ClassCustomization getCustomization() {
return classCustomization;
}
/**
* Gets type.
*
* @return Type.
*/
public Class<?> getType() {
return clazz;
}
/**
* Introspected customization for a class.
*
* @return Immutable class customization.
*/
public ClassCustomization getClassCustomization() {
return classCustomization;
}
/**
* Class model of parent class if present.
* @return class model of a parent
*/
public ClassModel getParentClassModel() {
return parentClassModel;
}
/**
* Get sorted class properties copy, combination of field and its getter / setter, javabeans alike.
* @return sorted class properties.
*/
public PropertyModel[] getSortedProperties() {
return sortedProperties;
}
/**
* Sets parsed properties of the class.
*
* @param parsedProperties class properties
*/
public void setProperties(List<PropertyModel> parsedProperties) {
sortedProperties = parsedProperties.toArray(new PropertyModel[]{});
this.properties = parsedProperties.stream().collect(Collectors.toMap(PropertyModel::getPropertyName, (mod) -> mod));
}
/**
* Get class properties copy, combination of field and its getter / setter, javabeans alike.
* @return class properties.
*/
public Map<String, PropertyModel> getProperties() {
return Collections.unmodifiableMap(properties);
}
/**
* Default no argument constructor of the class used for deserialization.
* @return default constructor
*/
public Constructor<?> getDefaultConstructor() {
return defaultConstructor;
}
}