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 package info.magnolia.ui.admincentral.shellapp.pulse.item;
35
36 import java.lang.reflect.InvocationTargetException;
37 import java.lang.reflect.Method;
38 import java.util.Map;
39
40 import com.vaadin.v7.data.Property;
41 import com.vaadin.v7.data.util.AbstractProperty;
42
43
44
45
46
47
48
49
50
51 public class NestedMapProperty<T> extends AbstractProperty<T> {
52
53 private final Object instance;
54 private String propertyName;
55 private Class<? extends T> type;
56 private Map map;
57
58 public NestedMapProperty(Object instance, String propertyName) {
59 this.instance = instance;
60 this.propertyName = propertyName;
61
62 initialize(instance.getClass(), propertyName);
63 }
64
65
66
67
68
69
70 @Override
71 public T getValue() {
72 return (T) map.get(propertyName);
73 }
74
75
76
77
78
79
80
81
82
83
84 @Override
85 public void setValue(T newValue) throws ReadOnlyException {
86
87 if (isReadOnly()) {
88 throw new Property.ReadOnlyException();
89 }
90 map.put(propertyName, newValue);
91 fireValueChange();
92 }
93
94 @Override
95 public Class<? extends T> getType() {
96 return type;
97 }
98
99 private void initialize(Class<?> beanClass, String propertyName)
100 throws IllegalArgumentException {
101
102 Class<?> propertyClass = beanClass;
103 String[] simplePropertyNames = propertyName.split("\\.");
104
105 if (propertyName.endsWith(".") || simplePropertyNames.length != 2) {
106 throw new IllegalArgumentException("Invalid property name '"
107 + propertyName + "'");
108 }
109
110 String simplePropertyName = simplePropertyNames[0].trim();
111 this.propertyName = simplePropertyNames[1].trim();
112
113 try {
114 Method getMethod = initGetterMethod(
115 simplePropertyName, propertyClass);
116 propertyClass = getMethod.getReturnType();
117
118 if (propertyClass.isAssignableFrom(Map.class)) {
119 this.map = ((Map) getMethod.invoke(instance));
120
121 Object object = map.get(this.propertyName);
122 if (object == null) {
123 throw new IllegalArgumentException("Value '"
124 + propertyName + "' is null.");
125 }
126 this.type = (Class<? extends T>) convertPrimitiveType(object.getClass());
127 }
128 else {
129 throw new IllegalArgumentException("Field '"
130 + simplePropertyName + "' is not a Map.");
131 }
132
133 } catch (NoSuchMethodException e) {
134 throw new IllegalArgumentException("No getter defined for '"
135 + simplePropertyName + "'.");
136 } catch (InvocationTargetException e) {
137 throw new IllegalArgumentException("Could not invoke getter defined for '"
138 + simplePropertyName + "'.");
139 } catch (IllegalAccessException e) {
140 throw new IllegalArgumentException("Could not access getter defined for '"
141 + simplePropertyName + "'.");
142 }
143
144
145 }
146
147
148
149
150
151
152
153
154
155
156
157
158 static Method initGetterMethod(String propertyName, final Class<?> beanClass)
159 throws NoSuchMethodException {
160 propertyName = propertyName.substring(0, 1).toUpperCase()
161 + propertyName.substring(1);
162
163 Method getMethod = null;
164 try {
165 getMethod = beanClass.getMethod("get" + propertyName,
166 new Class[] {});
167 } catch (final java.lang.NoSuchMethodException ignored) {
168 try {
169 getMethod = beanClass.getMethod("is" + propertyName,
170 new Class[] {});
171 } catch (final java.lang.NoSuchMethodException ignoredAsWell) {
172 getMethod = beanClass.getMethod("are" + propertyName,
173 new Class[] {});
174 }
175 }
176 return getMethod;
177 }
178
179 static Class<?> convertPrimitiveType(Class<?> type) {
180
181 if (type.isPrimitive()) {
182 if (type.equals(Boolean.TYPE)) {
183 type = Boolean.class;
184 } else if (type.equals(Integer.TYPE)) {
185 type = Integer.class;
186 } else if (type.equals(Float.TYPE)) {
187 type = Float.class;
188 } else if (type.equals(Double.TYPE)) {
189 type = Double.class;
190 } else if (type.equals(Byte.TYPE)) {
191 type = Byte.class;
192 } else if (type.equals(Character.TYPE)) {
193 type = Character.class;
194 } else if (type.equals(Short.TYPE)) {
195 type = Short.class;
196 } else if (type.equals(Long.TYPE)) {
197 type = Long.class;
198 }
199 }
200 return type;
201 }
202
203
204 }