View Javadoc

1   /*
2    * Copyright 2002-2005 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */	
16  package org.springframework.web.servlet.view.json.writer.sojo;
17  
18  import java.util.ArrayList;
19  import java.util.Collection;
20  import java.util.Iterator;
21  import java.util.List;
22  import java.util.Map;
23  
24  import net.sf.sojo.common.ObjectUtil;
25  import net.sf.sojo.common.WalkerInterceptor;
26  import net.sf.sojo.core.Constants;
27  import net.sf.sojo.core.conversion.ComplexBean2MapConversion;
28  import net.sf.sojo.core.filter.ClassPropertyFilterHandler;
29  import net.sf.sojo.core.reflect.ReflectionHelper;
30  import net.sf.sojo.util.ArrayIterator;
31  
32  /**
33   * Walk over (to traverse) object graph and collection information over path and values of the objects.
34   * This can use to transform one object graph to other representation (by registration of implementation from the interface <code>WalkerInterceptor</code>).
35   * 
36   * @author linke
37   *
38   */
39  public class MapGraphWalker {
40  
41  	@SuppressWarnings("unchecked")
42  	private List interceptorList = new ArrayList();
43  	private ObjectUtil objectUtil = new ObjectUtil(false);
44  	private int numberOfRecursion = 0;
45  	private boolean ignoreNullValues = true;
46  	private String excludedProperties[] = null;
47  	private String objectName;
48  	public MapGraphWalker() { 
49  		setIgnoreNullValues(true);
50  	}
51  	
52  	public MapGraphWalker(ClassPropertyFilterHandler pvFilterHandler) {
53  		this();
54  		this.objectUtil.setClassPropertyFilterHandler(pvFilterHandler);
55  	}
56  	
57  	public ObjectUtil getObjectUtil() { return objectUtil; }
58  	
59  	public void setExcludedProperties(String[] pvExcludedProperties) {
60  		excludedProperties = pvExcludedProperties;
61  	}
62  	
63  	public void setIgnoreNullValues(boolean pvBoolean) {
64  		ignoreNullValues = pvBoolean;
65  		ComplexBean2MapConversion lvBean2MapConversion = new ComplexBean2MapConversion();
66  		lvBean2MapConversion.setIgnoreNullValues(ignoreNullValues);
67  		objectUtil.getConverter().replaceConversion(lvBean2MapConversion);		
68  	}
69  	
70  	@SuppressWarnings("unchecked")
71  	public void addInterceptor(WalkerInterceptor pvInterceptor) {
72  		interceptorList.add(pvInterceptor);
73  	}
74  	public int getInterceptorSize() {
75  		return interceptorList.size();
76  	}
77  	public void removeInterceptorByNumber(int pvPosition) {
78  		interceptorList.remove(pvPosition);
79  	}
80  	
81  	private boolean fireVisitElementEvent(Object pvKey, int pvIndex, Object pvValue, int pvType, String pvPath, int pvNumberOfRecursion) {
82  		for (int i=0; i<interceptorList.size(); i++) {
83  			boolean b = ((WalkerInterceptor) interceptorList.get(i)).visitElement(pvKey, pvIndex, pvValue, pvType, pvPath, pvNumberOfRecursion);
84  			if (b == true) {
85  				return true;
86  			}
87  		}
88  		return false;
89  	}
90  
91  	private void fireVisitIterateableElement(Object pvValue, int pvType, String pvPath, int pvBeginEnd) {
92  		for (int i=0; i<interceptorList.size(); i++) {
93  			((WalkerInterceptor) interceptorList.get(i)).visitIterateableElement(pvValue, pvType, pvPath, pvBeginEnd);
94  		}
95  	}
96  
97  	
98  	
99  	private void fireStartWalk(Object pvStartObject) {
100 		for (int i=0; i<interceptorList.size(); i++) {
101 			((WalkerInterceptor) interceptorList.get(i)).startWalk(pvStartObject);
102 		}
103 	}
104 
105 	private void fireEndWalk() {
106 		for (int i=0; i<interceptorList.size(); i++) {
107 			((WalkerInterceptor) interceptorList.get(i)).endWalk();
108 		}
109 	}
110 	
111 	public int getNumberOfRecursion() { return numberOfRecursion; }
112 	
113 	public void walk(Object pvObject) {
114 		numberOfRecursion = 0;
115 		fireStartWalk(pvObject);
116 		walkInternal(null, Constants.INVALID_INDEX, pvObject, "");
117 		fireEndWalk();
118 	}
119 	
120 	public String removeLastPointOnPath(String pvPath) {
121 		String lvPath = pvPath;
122 		if (lvPath.endsWith(".")) {
123 			lvPath = lvPath.substring(0, lvPath.length() - 1);
124 		} 
125 		return lvPath; 
126 	}
127 	
128 	
129 	public boolean isPropertyExcluded(String property){
130 		String prob = removeLastPointOnPath(property);
131 		if(excludedProperties == null || excludedProperties.length == 0)
132 			return false;
133 		
134 		for(String excluded: excludedProperties){
135 			
136 			if(excluded != null && excluded.equals(prob))
137 				return true;
138 			if(!excluded.startsWith("(") && ("("+ objectName + ")." + excluded).equals(prob))
139 				return true;
140 		}
141 		
142 		return false;
143 	}
144 	
145 	@SuppressWarnings("unchecked")
146 	private void walkInternal(Object pvKey, int pvIndex, Object pvValue, String pvPath) {
147 		numberOfRecursion++;
148 		
149 		if(!isPropertyExcluded(pvPath)){
150 			if (pvValue == null) {
151 				fireVisitElementEvent(pvKey, pvIndex, null, Constants.TYPE_NULL, removeLastPointOnPath(pvPath), numberOfRecursion);
152 			} else if (ReflectionHelper.isSimpleType(pvValue)) {
153 				fireVisitElementEvent(pvKey, pvIndex, pvValue, Constants.TYPE_SIMPLE, removeLastPointOnPath(pvPath), numberOfRecursion);
154 			}
155 				
156 			// --- Map ---
157 			else if (ReflectionHelper.isMapType(pvValue)) {
158 				Map lvMap = (Map) pvValue;
159 				boolean lvCancel = fireVisitElementEvent(pvKey, pvIndex, pvValue, Constants.TYPE_MAP, pvPath + "()", numberOfRecursion);
160 				if (ReflectionHelper.isComplexMapType(pvValue)) {
161 					if (pvPath.length() > 0 && pvPath.endsWith(".") == false) { pvPath = pvPath + "."; }
162 					mapWalker(lvMap, pvPath, false, lvCancel);
163 				} else {
164 					mapWalker(lvMap, pvPath, true, lvCancel);
165 				}
166 			}
167 				
168 			// --- Iterateable ---
169 			else if (ReflectionHelper.isIterateableType(pvValue)) {
170 				boolean lvCancel =  fireVisitElementEvent(pvKey, pvIndex, pvValue, Constants.TYPE_ITERATEABLE, pvPath + "[]", numberOfRecursion);
171 				iteratorWalker(pvValue, pvPath, lvCancel);
172 			}
173 				
174 			// --- Complex ---
175 			else {
176 				pvPath = removeLastPointOnPath(pvPath);
177 				Object lvSimple = objectUtil.makeSimple(pvValue, excludedProperties);
178 				if("".equals(pvKey) || pvKey == null)
179 					walkInternal(null, Constants.INVALID_INDEX, lvSimple, pvPath);
180 				else
181 					walkInternal(pvKey, Constants.INVALID_INDEX, lvSimple, pvPath);
182 			}
183 		}
184 	}
185 			
186 	@SuppressWarnings("unchecked")
187 	private void iteratorWalker(Object pvValue , String pvPath, boolean pvCancel) {
188 		if(!isPropertyExcluded(pvPath)){
189 		if (pvCancel == false) {
190 			int lvIndex = Constants.INVALID_INDEX;
191 			
192 			Iterator lvIterator = null;
193 			if (pvValue.getClass().isArray()) {
194 				lvIterator = new ArrayIterator(pvValue);
195 			} else {
196 				Collection lvCollection = (Collection) pvValue;
197 				lvIterator = lvCollection.iterator();
198 			}
199 			
200 			fireVisitIterateableElement(pvValue, Constants.TYPE_ITERATEABLE, pvPath, Constants.ITERATOR_BEGIN);
201 			while (lvIterator.hasNext()) {
202 				Object o = lvIterator.next();
203 				lvIndex++;
204 				StringBuffer sb = new StringBuffer(pvPath);
205 				sb.append("[").append(lvIndex).append("]");
206 				sb.append(".");
207 				walkInternal(null, lvIndex, o, sb.toString());
208 			}
209 			fireVisitIterateableElement(pvValue, Constants.TYPE_ITERATEABLE, pvPath, Constants.ITERATOR_END);
210 		}
211 		}
212 	}
213 	
214 	@SuppressWarnings("unchecked")
215 	private void mapWalker(Map pvMap, String pvPath, boolean pvWithBrackets, boolean pvCancel) {
216 		if(!isPropertyExcluded(pvPath)){
217 			if (pvCancel == false) {
218 				fireVisitIterateableElement(pvMap, Constants.TYPE_MAP, pvPath, Constants.ITERATOR_BEGIN);
219 				Iterator lvIterator = pvMap.entrySet().iterator();
220 				while (lvIterator.hasNext()) {
221 					Map.Entry lvEntry = (Map.Entry) lvIterator.next();
222 					Object lvKey = lvEntry.getKey();
223 					Object lvValue = lvEntry.getValue();
224 					StringBuffer sb = new StringBuffer(pvPath);
225 					if (pvWithBrackets) {
226 						sb.append("(").append(lvKey).append(")");
227 						sb.append(".");
228 					} else {
229 						sb.append(lvKey);
230 					}
231 					walkInternal(lvKey, Constants.INVALID_INDEX, lvValue, sb.toString());
232 				}
233 				fireVisitIterateableElement(pvMap, Constants.TYPE_MAP, pvPath, Constants.ITERATOR_END);
234 			}
235 		}
236 	}
237 
238 	public void setObjectName(String objectName) {
239 		this.objectName = objectName;
240 	}
241 
242 	
243 }