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.map2bean;
35
36 import static java.util.stream.Collectors.toList;
37
38 import info.magnolia.jcr.node2bean.PropertyTypeDescriptor;
39 import info.magnolia.jcr.node2bean.TypeDescriptor;
40 import info.magnolia.transformer.TransformationProblem;
41
42 import java.util.ArrayDeque;
43 import java.util.ArrayList;
44 import java.util.Deque;
45 import java.util.Iterator;
46 import java.util.List;
47 import java.util.Map;
48 import java.util.Optional;
49 import java.util.StringJoiner;
50 import java.util.function.Function;
51
52 import org.apache.commons.lang3.StringUtils;
53
54
55
56
57
58
59
60
61
62
63
64 public class TransformationState {
65
66
67
68
69 class Entry {
70 String name;
71 Object value;
72 TypeDescriptor typeDescriptor;
73 TypeDescriptor genericTypeDescriptor;
74
75 Entry(String name, Object value, TypeDescriptor typeDescriptor, TypeDescriptor genericType) {
76 this.name = name;
77 this.value = value;
78 this.typeDescriptor = typeDescriptor;
79 this.genericTypeDescriptor = genericType;
80 }
81 }
82
83 private final List<TransformationProblem> problems = new ArrayList<>();
84 private final Deque<Entry> entries = new ArrayDeque<>();
85
86 void pushEntry(String name, Object value, TypeDescriptor typeDescriptor) {
87 this.pushEntry(name, value, typeDescriptor, null);
88 }
89
90 public void pushEntry(String name, Object value, PropertyTypeDescriptor typeDescriptor) {
91 this.pushEntry(name, value, typeDescriptor.getType(), typeDescriptor.getCollectionEntryType());
92 }
93
94 void pushEntry(String name, Object value, TypeDescriptor typeDescriptor, TypeDescriptor genericTypeDescriptor) {
95 entries.push(new Entry(name, value, typeDescriptor, genericTypeDescriptor));
96 }
97
98 public void popCurrentEntry() {
99 entries.pop();
100 }
101
102 Entry peek() {
103 return entries.peek();
104 }
105
106 String peekName() {
107 return entries.peek().name;
108 }
109
110 TypeDescriptor peekTypeDescriptor() {
111 return entries.peek().typeDescriptor;
112 }
113
114 Object peekValue() {
115 return entries.peek().value;
116 }
117
118 List<?> peekList() {
119 return getListValue(entries.peek().value);
120 }
121
122 Map<String, Object> peekMap() {
123 if (entries.peek().value instanceof Map) {
124 return (Map<String, Object>) entries.peek().value;
125 }
126 return null;
127 }
128
129 List<TransformationProblem> getProblems() {
130 return problems;
131 }
132
133 String currentPath() {
134 final StringJoiner joiner = new StringJoiner("/");
135 for (final Iterator<Entry> entryIterator = entries.descendingIterator(); entryIterator.hasNext(); ) {
136 Entry next = entryIterator.next();
137 joiner.add(Optional.ofNullable(next.value)
138 .filter(Map.class::isInstance)
139 .map(Map.class::cast)
140 .map(map -> map.get("name"))
141 .map(Object::toString)
142 .orElse(next.name)
143 );
144 }
145 return StringUtils.defaultIfBlank(String.join("/", joiner.toString()), "/");
146 }
147
148 public void trackProblem(TransformationProblem.Builder problemBuilder) {
149 problems.add(problemBuilder.withLocation(currentPath()).build());
150 }
151
152 private static List<Object> getListValue(Object value) {
153 if (value instanceof List) {
154 return (List<Object>) value;
155 }
156
157 if (value instanceof Map) {
158 final Map<String, Object> map = (Map) value;
159 final Function<Map.Entry<String, Object>, Object> entry2Value = new Function<Map.Entry<String, Object>, Object>() {
160 @Override
161 public Object apply(Map.Entry<String, Object> input) {
162 final Object returnValue = input.getValue();
163 if (returnValue instanceof Map) {
164 final Map mapValue = (Map) returnValue;
165 if (!mapValue.containsKey("name")) {
166 mapValue.put("name", input.getKey());
167 }
168 }
169 return returnValue;
170 }
171 };
172 return map.entrySet().stream().map(entry2Value).collect(toList());
173 }
174
175 return null;
176 }
177 }