View Javadoc

1   /*
2    * Copyright 2004-2005, 2007-2008 the original author or authors.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5    * use this file except in compliance with the License. You may obtain a copy of
6    * 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, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations under
14   * the License.
15   */
16  package net.sf.morph.transform.copiers;
17  
18  import java.util.Locale;
19  import java.util.Map;
20  
21  import net.sf.composite.util.ObjectUtils;
22  import net.sf.morph.transform.DecoratedConverter;
23  import net.sf.morph.transform.DecoratedCopier;
24  import net.sf.morph.transform.NodeCopier;
25  import net.sf.morph.transform.Transformer;
26  import net.sf.morph.transform.transformers.BaseReflectorTransformer;
27  import net.sf.morph.util.TransformerUtils;
28  
29  /**
30   * Base class for copiers that copy information from one bean to another based
31   * on the property names in the source and destination objects.
32   * 
33   * @author Matt Sgarlata
34   * @author Alexander Volanis
35   * @since Feb 5, 2005
36   */
37  public abstract class BasePropertyNameCopier extends BaseReflectorTransformer implements
38  		DecoratedCopier, DecoratedConverter, NodeCopier {
39  
40  	private static final Class[] SOURCE_AND_DESTINATION_TYPES = { Object.class };
41  
42  	private boolean errorOnMissingProperty = false;
43  	private Map propertyTransformers;
44  
45  	/**
46  	 * Create a new BasePropertyNameCopier.
47  	 */
48  	public BasePropertyNameCopier() {
49  		super();
50  	}
51  
52  	/**
53  	 * Create a new BasePropertyNameCopier.
54  	 * @param errorOnMissingProperty
55  	 */
56  	public BasePropertyNameCopier(boolean errorOnMissingProperty) {
57  		super();
58  		this.errorOnMissingProperty = errorOnMissingProperty;
59  	}
60  
61  	/**
62  	 * {@inheritDoc}
63  	 */
64  	public Object createReusableSource(Class destinationClass, Object source) {
65  		return super.createReusableSource(destinationClass, source);
66  	}
67  
68      /**
69  	 * Return <code>true</code> if errors should should be thrown when a
70  	 * property is missing.
71  	 * 
72  	 * @return <code>true</code> if errors should be thrown when a property is
73  	 *         missing or <br>
74  	 *         <code>false</code>, otherwise.
75  	 */
76  	public boolean isErrorOnMissingProperty() {
77  		return errorOnMissingProperty;
78  	}
79  
80  	/**
81  	 * Set the value of the errorOnMissingProperty flag.
82  	 * 
83  	 * @param errorOnMissingProperty
84  	 *            The value of errorOnMissingProperty to set.
85  	 */
86  	public void setErrorOnMissingProperty(boolean isStrict) {
87  		this.errorOnMissingProperty = isStrict;
88  	}
89  
90  	/**
91  	 * Choose the appropriate property transformer.
92  	 * @param sourceProperty
93  	 * @param source
94  	 * @param destinationProperty
95  	 * @param destination
96  	 * @param locale
97  	 * @param preferredTransformationType
98  	 * @return
99  	 */
100 	protected Transformer chooseTransformer(String sourceProperty, Object source,
101 			String destinationProperty, Object destination, Locale locale,
102 			Integer preferredTransformationType) {
103 		Map m = getPropertyTransformers();
104 		if (m != null) {
105 			Transformer t = (Transformer) m.get(sourceProperty);
106 			if (t != null) {
107 				if (t instanceof NodeCopier) {
108 					NodeCopier nc = (NodeCopier) t;
109 					if (nc.getNestedTransformer() == null) {
110 						nc.setNestedTransformer(getNestedTransformer());
111 					}
112 				}
113 				return t;
114 			}
115 		}
116 		return getNestedTransformer();	
117 	}
118 
119 	/**
120 	 * Perform the specified property copy.
121 	 * @param sourceProperty
122 	 * @param source
123 	 * @param destinationProperty
124 	 * @param destination
125 	 * @param locale
126 	 * @param preferredTransformationType
127 	 */
128 	protected void copyProperty(String sourceProperty, Object source,
129 			String destinationProperty, Object destination, Locale locale,
130 			Integer preferredTransformationType) {
131 		if (getLog().isTraceEnabled()) {
132 			getLog().trace(
133 				"Copying property '" + sourceProperty + "' of "
134 					+ ObjectUtils.getObjectDescription(source)
135 					+ " to property '" + destinationProperty + "' of "
136 					+ ObjectUtils.getObjectDescription(destination));
137 		}
138 
139 		// determine the destination type
140 		Class destinationType = getBeanReflector().getType(
141 			destination, destinationProperty);
142 		// determine the value of the source property
143 		Object sourceValue = getBeanReflector().get(source,
144 			sourceProperty);
145 		// determine the current value of the destination property, if any
146 		Object destinationValue = null;
147 		if (getBeanReflector().isReadable(destination, destinationProperty)) {
148 			destinationValue = getBeanReflector().get(destination,
149 					destinationProperty);	
150 		}
151 		//possibly override preferredTransformationType:
152 		preferredTransformationType = getPreferredTransformationType(source,
153 				sourceProperty, sourceValue, destination, destinationProperty,
154 				destinationValue, locale, preferredTransformationType);
155 		// choose a transformer to use
156 		Transformer transformer = chooseTransformer(sourceProperty,
157 			source, destinationProperty, destination, locale,
158 			preferredTransformationType);
159 		// determine the new value that will be set on the destination
160 		Object newDestinationValue = TransformerUtils.transform(transformer,
161 			destinationType, destinationValue, sourceValue, locale,
162 			preferredTransformationType);
163 		// set the transformed value on the destination
164 		getBeanReflector().set(destination, destinationProperty,
165 			newDestinationValue);
166 
167 		if (getLog().isTraceEnabled()) {
168 			getLog().trace(
169 				"Done copying property '" + sourceProperty
170 					+ "' to property '" + destinationProperty
171 					+ "'.  sourceValue was "
172 					+ ObjectUtils.getObjectDescription(sourceValue)
173 					+ " and destinationValue was "
174 					+ ObjectUtils.getObjectDescription(destinationValue));
175 		}
176 	}
177 
178 	/**
179 	 * Extension point for subclasses to override preferredTransformationType. 
180 	 * @param source
181 	 * @param sourceProperty
182 	 * @param sourceValue
183 	 * @param destination
184 	 * @param destinationProperty
185 	 * @param destinationValue
186 	 * @param locale
187 	 * @param preferredTransformationType
188 	 * @return Integer
189 	 * @see Transformer
190 	 */
191 	protected Integer getPreferredTransformationType(Object source,
192 			String sourceProperty, Object sourceValue, Object destination,
193 			String destinationProperty, Object destinationValue, Locale locale,
194 			Integer preferredTransformationType) {
195 		return preferredTransformationType;
196 	}
197 
198 	/**
199 	 * {@inheritDoc}
200 	 */
201 	protected boolean isWrappingRuntimeExceptions() {
202 		// this transformer can recursively call other transformers, so we don't
203 		// want to eat user defined exceptions
204 	    return false;
205     }
206 
207 	/**
208 	 * {@inheritDoc}
209 	 */
210 	// overridden to make this public
211 	public Transformer getNestedTransformer() {
212 		return super.getNestedTransformer();
213 	}
214 
215 	/**
216 	 * {@inheritDoc}
217 	 */
218 	// overridden to make this public
219 	public void setNestedTransformer(Transformer transformer) {
220 		super.setNestedTransformer(transformer);
221 	}
222 
223 	/**
224 	 * Get the Map of Transformers to use instead of <code>nestedTransformer</code>.
225 	 * @return Map
226 	 */
227 	public Map getPropertyTransformers() {
228 		return propertyTransformers;
229 	}
230 
231 	/**
232 	 * Set the Map of Transformers to use instead of <code>nestedTransformer</code>.
233 	 * @param propertyTransformers
234 	 */
235 	public void setPropertyTransformers(Map propertyTransformers) {
236 		this.propertyTransformers = propertyTransformers;
237 	}
238 
239 	/**
240 	 * {@inheritDoc}
241 	 */
242 	protected Class[] getSourceClassesImpl() throws Exception {
243 		return SOURCE_AND_DESTINATION_TYPES;
244 	}
245 
246 	/**
247 	 * {@inheritDoc}
248 	 */
249 	public void setSourceClasses(Class[] sourceClasses) {
250 		super.setSourceClasses(sourceClasses);
251 	}
252 
253 	/**
254 	 * {@inheritDoc}
255 	 */
256 	protected Class[] getDestinationClassesImpl() throws Exception {
257 		return SOURCE_AND_DESTINATION_TYPES;
258 	}
259 
260 	/**
261 	 * {@inheritDoc}
262 	 */
263 	public void setDestinationClasses(Class[] destinationClasses) {
264 		super.setDestinationClasses(destinationClasses);
265 	}
266 }