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.jcr.node2bean.impl;
35
36 import info.magnolia.jcr.node2bean.PropertyTypeDescriptor;
37 import info.magnolia.jcr.node2bean.TransformationState;
38 import info.magnolia.jcr.node2bean.TypeDescriptor;
39 import info.magnolia.jcr.node2bean.TypeMapping;
40 import info.magnolia.objectfactory.ComponentProvider;
41
42 import java.lang.reflect.Array;
43 import java.lang.reflect.Method;
44 import java.util.ArrayList;
45 import java.util.Collection;
46 import java.util.LinkedHashMap;
47 import java.util.List;
48 import java.util.Map;
49 import java.util.Map.Entry;
50 import java.util.stream.Collectors;
51
52 import javax.jcr.RepositoryException;
53
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
56
57
58
59
60 public class CollectionPropertyHidingTransformer extends Node2BeanTransformerImpl {
61
62 private static final Logger log = LoggerFactory.getLogger(CollectionPropertyHidingTransformer.class);
63
64 private Class<?> beanClass;
65
66 private String collectionName;
67
68 private TypeDescriptor type;
69
70 private PropertyTypeDescriptor propertyDescriptor;
71
72 private Method writeMethod;
73
74 private TypeDescriptor propertyType;
75
76
77
78
79
80 public CollectionPropertyHidingTransformer(Class<?> beanClass, String collectionName) {
81 this.beanClass = beanClass;
82 this.collectionName = collectionName;
83 }
84
85 @Override
86 protected TypeDescriptorypeDescriptor">TypeDescriptor onResolveType(TypeMapping typeMapping, TransformationState state, TypeDescriptor resolvedType, ComponentProvider componentProvider) {
87
88 if (type == null) {
89 type = typeMapping.getTypeDescriptor(beanClass);
90 propertyDescriptor = type.getPropertyTypeDescriptor(collectionName, typeMapping);
91 writeMethod = propertyDescriptor.getWriteMethod();
92 propertyType = propertyDescriptor.getCollectionEntryType();
93 }
94
95 if (resolvedType == null) {
96
97
98
99
100
101 if (state.getLevel() > 1 && state.getCurrentType().equals(type)) {
102
103
104 resolvedType = getPropertyType();
105 }
106 }
107 return resolvedType;
108 }
109
110 @Override
111 public void setProperty(TypeMapping mapping, TransformationState state, PropertyTypeDescriptor descriptor, Map<String, Object> values) throws RepositoryException {
112 if (descriptor.getName().equals(collectionName)) {
113 Object bean = state.getCurrentBean();
114
115 Map<String, Object> value = values.entrySet().stream()
116 .filter(this::canHandleValue)
117 .collect(Collectors.toMap(Entry::getKey, Entry::getValue,
118 (u, v) -> {
119 throw new IllegalStateException(String.format("Duplicate key %s", u));
120 },
121 LinkedHashMap::new));
122
123 try {
124 if (propertyDescriptor.isMap()) {
125 writeMethod.invoke(bean, value);
126 } else if (propertyDescriptor.isArray()) {
127 Class<?> entryClass = getPropertyType().getType();
128 List<Object> list = new ArrayList<>(value.values());
129
130 Object[] arr = (Object[]) Array.newInstance(entryClass, list.size());
131
132 for (int i = 0; i < arr.length; i++) {
133 arr[i] = list.get(i);
134 }
135 writeMethod.invoke(bean, new Object[]{arr});
136 } else if (propertyDescriptor.isCollection()) {
137 Collection<?> collection = createCollectionFromMap(value, propertyDescriptor.getType().getType());
138 writeMethod.invoke(bean, collection);
139 }
140 } catch (Exception e) {
141 log.error("Can't call set method {}", propertyDescriptor.getWriteMethod(), e);
142 }
143 } else {
144 super.setProperty(mapping, state, descriptor, values);
145 }
146 }
147
148 @Override
149 public boolean canHandleValue(TypeMapping typeMapping, TransformationState state, PropertyTypeDescriptor descriptor, Entry<String, Object> value) {
150 return canHandleValue(value) || super.canHandleValue(typeMapping, state, descriptor, value);
151 }
152
153 private boolean canHandleValue(Entry<String, Object> entry) {
154 return getPropertyType().getType().isInstance(entry.getValue());
155 }
156
157 @Override
158 public boolean supportsValueClaims() {
159
160 return getClass().equals(CollectionPropertyHidingTransformer.class);
161 }
162
163 public TypeDescriptor getPropertyType() {
164 return propertyType;
165 }
166 }