1 | |
|
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
package org.yaml.snakeyaml.introspector; |
17 | |
|
18 | |
import java.beans.IntrospectionException; |
19 | |
import java.beans.Introspector; |
20 | |
import java.beans.PropertyDescriptor; |
21 | |
import java.lang.reflect.Field; |
22 | |
import java.lang.reflect.Method; |
23 | |
import java.lang.reflect.Modifier; |
24 | |
import java.util.Collection; |
25 | |
import java.util.HashMap; |
26 | |
import java.util.LinkedHashMap; |
27 | |
import java.util.Map; |
28 | |
import java.util.Set; |
29 | |
import java.util.TreeSet; |
30 | |
|
31 | |
import org.yaml.snakeyaml.error.YAMLException; |
32 | |
|
33 | 132937 | public class PropertyUtils { |
34 | |
|
35 | 132937 | private final Map<Class<?>, Map<String, Property>> propertiesCache = new HashMap<Class<?>, Map<String, Property>>(); |
36 | 132937 | private final Map<Class<?>, Set<Property>> readableProperties = new HashMap<Class<?>, Set<Property>>(); |
37 | 132937 | private BeanAccess beanAccess = BeanAccess.DEFAULT; |
38 | 132937 | private boolean allowReadOnlyProperties = false; |
39 | 132937 | private boolean skipMissingProperties = false; |
40 | |
|
41 | |
protected Map<String, Property> getPropertiesMap(Class<?> type, BeanAccess bAccess) |
42 | |
throws IntrospectionException { |
43 | 14880 | if (propertiesCache.containsKey(type)) { |
44 | 2346 | return propertiesCache.get(type); |
45 | |
} |
46 | |
|
47 | 12534 | Map<String, Property> properties = new LinkedHashMap<String, Property>(); |
48 | 12534 | boolean inaccessableFieldsExist = false; |
49 | 12534 | switch (bAccess) { |
50 | |
case FIELD: |
51 | 90 | for (Class<?> c = type; c != null; c = c.getSuperclass()) { |
52 | 127 | for (Field field : c.getDeclaredFields()) { |
53 | 67 | int modifiers = field.getModifiers(); |
54 | 67 | if (!Modifier.isStatic(modifiers) && !Modifier.isTransient(modifiers) |
55 | |
&& !properties.containsKey(field.getName())) { |
56 | 61 | properties.put(field.getName(), new FieldProperty(field)); |
57 | |
} |
58 | |
} |
59 | |
} |
60 | 30 | break; |
61 | |
default: |
62 | |
|
63 | |
for (PropertyDescriptor property : Introspector.getBeanInfo(type) |
64 | 26285 | .getPropertyDescriptors()) { |
65 | 13781 | Method readMethod = property.getReadMethod(); |
66 | 13781 | if (readMethod == null || !readMethod.getName().equals("getClass")) { |
67 | 1277 | properties.put(property.getName(), new MethodProperty(property)); |
68 | |
} |
69 | |
} |
70 | |
|
71 | |
|
72 | 37569 | for (Class<?> c = type; c != null; c = c.getSuperclass()) { |
73 | 83524 | for (Field field : c.getDeclaredFields()) { |
74 | 58459 | int modifiers = field.getModifiers(); |
75 | 58459 | if (!Modifier.isStatic(modifiers) && !Modifier.isTransient(modifiers)) { |
76 | 58435 | if (Modifier.isPublic(modifiers)) { |
77 | 57151 | properties.put(field.getName(), new FieldProperty(field)); |
78 | |
} else { |
79 | 1284 | inaccessableFieldsExist = true; |
80 | |
} |
81 | |
} |
82 | |
} |
83 | |
} |
84 | |
break; |
85 | |
} |
86 | 12534 | if (properties.isEmpty() && inaccessableFieldsExist) { |
87 | 4 | throw new YAMLException("No JavaBean properties found in " + type.getName()); |
88 | |
} |
89 | 12530 | propertiesCache.put(type, properties); |
90 | 12530 | return properties; |
91 | |
} |
92 | |
|
93 | |
public Set<Property> getProperties(Class<? extends Object> type) throws IntrospectionException { |
94 | 45033 | return getProperties(type, beanAccess); |
95 | |
} |
96 | |
|
97 | |
public Set<Property> getProperties(Class<? extends Object> type, BeanAccess bAccess) |
98 | |
throws IntrospectionException { |
99 | 45033 | if (readableProperties.containsKey(type)) { |
100 | 32758 | return readableProperties.get(type); |
101 | |
} |
102 | 12275 | Set<Property> properties = createPropertySet(type, bAccess); |
103 | 12271 | readableProperties.put(type, properties); |
104 | 12271 | return properties; |
105 | |
} |
106 | |
|
107 | |
protected Set<Property> createPropertySet(Class<? extends Object> type, BeanAccess bAccess) |
108 | |
throws IntrospectionException { |
109 | 12274 | Set<Property> properties = new TreeSet<Property>(); |
110 | 12274 | Collection<Property> props = getPropertiesMap(type, bAccess).values(); |
111 | 12270 | for (Property property : props) { |
112 | 57710 | if (property.isReadable() && (allowReadOnlyProperties || property.isWritable())) { |
113 | 57695 | properties.add(property); |
114 | |
} |
115 | |
} |
116 | 12270 | return properties; |
117 | |
} |
118 | |
|
119 | |
public Property getProperty(Class<? extends Object> type, String name) |
120 | |
throws IntrospectionException { |
121 | 2605 | return getProperty(type, name, beanAccess); |
122 | |
} |
123 | |
|
124 | |
public Property getProperty(Class<? extends Object> type, String name, BeanAccess bAccess) |
125 | |
throws IntrospectionException { |
126 | 2605 | Map<String, Property> properties = getPropertiesMap(type, bAccess); |
127 | 2605 | Property property = properties.get(name); |
128 | 2605 | if (property == null && skipMissingProperties) { |
129 | 2 | property = new MissingProperty(name); |
130 | |
} |
131 | 2605 | if (property == null || !property.isWritable()) { |
132 | 15 | throw new YAMLException("Unable to find property '" + name + "' on class: " |
133 | |
+ type.getName()); |
134 | |
} |
135 | 2590 | return property; |
136 | |
} |
137 | |
|
138 | |
public void setBeanAccess(BeanAccess beanAccess) { |
139 | 47 | if (this.beanAccess != beanAccess) { |
140 | 21 | this.beanAccess = beanAccess; |
141 | 21 | propertiesCache.clear(); |
142 | 21 | readableProperties.clear(); |
143 | |
} |
144 | 47 | } |
145 | |
|
146 | |
public void setAllowReadOnlyProperties(boolean allowReadOnlyProperties) { |
147 | 132936 | if (this.allowReadOnlyProperties != allowReadOnlyProperties) { |
148 | 13 | this.allowReadOnlyProperties = allowReadOnlyProperties; |
149 | 13 | readableProperties.clear(); |
150 | |
} |
151 | 132936 | } |
152 | |
|
153 | |
|
154 | |
|
155 | |
|
156 | |
|
157 | |
|
158 | |
|
159 | |
|
160 | |
public void setSkipMissingProperties(boolean skipMissingProperties) { |
161 | 2 | if (this.skipMissingProperties != skipMissingProperties) { |
162 | 1 | this.skipMissingProperties = skipMissingProperties; |
163 | 1 | readableProperties.clear(); |
164 | |
} |
165 | 2 | } |
166 | |
} |