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