fixing comparing rank terms
[cdmlib.git] / cdmlib-remote / src / main / java / eu / etaxonomy / cdm / remote / json / processor / bean / AbstractBeanProcessor.java
1 // $Id$
2 /**
3 * Copyright (C) 2009 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
6 *
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
9 */
10 package eu.etaxonomy.cdm.remote.json.processor.bean;
11
12 import java.beans.PropertyDescriptor;
13 import java.lang.reflect.InvocationTargetException;
14 import java.util.Collection;
15 import java.util.HashSet;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.Set;
19
20 import net.sf.json.JSONException;
21 import net.sf.json.JSONObject;
22 import net.sf.json.JsonConfig;
23 import net.sf.json.processors.JsonBeanProcessor;
24 import net.sf.json.processors.JsonValueProcessor;
25 import net.sf.json.processors.JsonVerifier;
26 import net.sf.json.util.PropertyFilter;
27
28 import org.apache.commons.beanutils.PropertyUtils;
29 import org.apache.log4j.Logger;
30 import org.hibernate.Hibernate;
31
32 import eu.etaxonomy.cdm.model.common.CdmBase;
33 import eu.etaxonomy.cdm.model.location.NamedArea;
34 import eu.etaxonomy.cdm.persistence.dao.AbstractBeanInitializer;
35
36 /**
37 * @author a.kohlbecker
38 * @date 30.03.2009
39 *
40 */
41 public abstract class AbstractBeanProcessor<T extends Object> implements JsonBeanProcessor{
42
43 public static final Logger logger = Logger.getLogger(AbstractBeanProcessor.class);
44
45 private Set<String> excludes = new HashSet<String>();
46
47 public Set<String> getExcludes() {
48 return excludes;
49 }
50
51 /**
52 * This method allows supplying a List of property names to be ignored
53 * during the serialization to JSON. The <code>excludes</code> will be
54 * merged with the property names configured by subclasses which override
55 * {@link {@link #getIgnorePropNames()}.
56 *
57 * @param excludes
58 */
59 public void setExcludes(Set<String> excludes) {
60 this.excludes = excludes;
61 }
62
63 /**
64 * Implementations of this abstract class may override this method in order
65 * to supply a List of property names to be ignored in
66 * {@link #processBean(Object, JsonConfig)}. This feature generally is used
67 * when {@link #processBeanSecondStep(CdmBase, JSONObject, JsonConfig)} is
68 * implemented. such that this method is responsible of serializing this
69 * property.
70 *
71 * @return a List of property names.
72 */
73 public abstract List<String> getIgnorePropNames();
74
75 /**
76 * merges and returns {@link {@link #getIgnorePropNames()} with
77 * {@link #excludes}
78 *
79 * @return
80 */
81 protected Set<String> getMergedExcludes(){
82 Set<String> mergedExcludes = new HashSet<String>(excludes);
83 if(getIgnorePropNames() != null){
84 mergedExcludes.addAll(getIgnorePropNames());
85 }
86 return mergedExcludes;
87 }
88
89 /**
90 *
91 * @param json
92 * @param jsonConfig
93 * @param fieldName
94 * @param fieldObject
95 */
96 protected void addJsonElement(JSONObject json, JsonConfig jsonConfig, String fieldName, Object fieldObject) {
97 if(Hibernate.isInitialized(fieldObject)){
98 json.element(fieldName, fieldObject, jsonConfig);
99 }
100 }
101
102
103 /* (non-Javadoc)
104 * @see net.sf.json.processors.JsonBeanProcessor#processBean(java.lang.Object, net.sf.json.JsonConfig)
105 */
106 public final JSONObject processBean(Object bean, JsonConfig jsonConfig) {
107
108 if(logger.isDebugEnabled()){
109 logger.debug("processing " + bean.getClass());
110 }
111
112 JSONObject json = new JSONObject();
113 Collection exclusions = jsonConfig.getMergedExcludes( bean.getClass() );
114 Set<Class> typeRestrictions = new HashSet<Class>();
115 typeRestrictions.add(CdmBase.class);
116 Set<PropertyDescriptor> props = AbstractBeanInitializer.getProperties(bean, null);
117 PropertyFilter jsonPropertyFilter = jsonConfig.getJsonPropertyFilter();
118 for(PropertyDescriptor prop: props){
119 String key = prop.getName();
120 if(getMergedExcludes().contains(key) || exclusions.contains(key)){
121 if(logger.isDebugEnabled()){
122 logger.debug("skipping excluded property " + key);
123 }
124 continue;
125 }
126
127 try {
128 // ------ reusing snippet from JSONOnbject._fromBean()
129 Class type = prop.getPropertyType();
130 Object value = PropertyUtils.getProperty( bean, key );
131
132 if( jsonPropertyFilter != null && jsonPropertyFilter.apply( bean, key, value ) ){
133 continue;
134 }
135 JsonValueProcessor jsonValueProcessor = jsonConfig.findJsonValueProcessor(bean.getClass(), type, key );
136 if( jsonValueProcessor != null ){
137 value = jsonValueProcessor.processObjectValue( key, value, jsonConfig );
138 if( !JsonVerifier.isValidJsonValue( value ) ){
139 throw new JSONException( "Value is not a valid JSON value. " + value );
140 }
141 }
142 // ----- END of snipped
143 if(logger.isDebugEnabled()){
144 logger.debug("processing " + key + " of " + bean.getClass());
145 }
146 if(CdmBase.class.isAssignableFrom(type)){
147 json.element(key, value, jsonConfig);
148 } else if(Collection.class.isAssignableFrom(type) || Map.class.isAssignableFrom(type)){
149 json.element(key, value, jsonConfig);
150 } else if(Object.class.isAssignableFrom(type)){
151 json.element(key, value, jsonConfig);
152 } else {
153 json.element(key, value);
154 }
155
156 } catch (IllegalAccessException e) {
157 logger.error(e.getMessage(), e);
158 } catch (InvocationTargetException e) {
159 logger.error(e.getMessage(), e);
160 } catch (NoSuchMethodException e) {
161 logger.error(e.getMessage(), e);
162 }
163 }
164
165 json = processBeanSecondStep((T) bean, json, jsonConfig);
166
167 return json;
168 }
169
170 /**
171 * This method is called ate the end of {@link #processBean(Object, JsonConfig)} just before the JSONObject is returned.
172 * By overriding this method it is possible to to further processing.
173 * <p>
174 * <b>See also {@link #getIgnorePropNames()}!</b>
175 *
176 * @param bean
177 * @param json
178 * @param jsonConfig
179 * @return
180 */
181 public abstract JSONObject processBeanSecondStep(T bean, JSONObject json, JsonConfig jsonConfig) ;
182
183
184 }