001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019:
020: package org.apache.axis2.jaxws.utility;
021:
022: import org.apache.axis2.jaxws.ExceptionFactory;
023: import org.apache.axis2.jaxws.i18n.Messages;
024: import org.apache.axis2.jaxws.wrapper.impl.JAXBWrapperException;
025: import org.apache.commons.logging.Log;
026: import org.apache.commons.logging.LogFactory;
027:
028: import java.beans.IndexedPropertyDescriptor;
029: import java.beans.PropertyDescriptor;
030: import java.lang.reflect.InvocationTargetException;
031: import java.lang.reflect.Method;
032: import java.util.Collection;
033:
034: /**
035: * A PropertyDescriptor provides acesss to a bean property. Values can be queried/changed using the
036: * read and writer methods of the PropertyDescriptor.
037: * <p/>
038: * A PropertyDescriptorPlus object wraps a PropertyDescriptor and supplies enhanced set/get methods
039: * that match JAXB semantis.
040: * <p/>
041: * For example, the set(..) method is smart enough to add lists, arrays and atomic values on JAXB
042: * beans.
043: * <p/>
044: * The PropertyDescriptorPlus object also stores the xmlName of the property.
045: *
046: * @See XMLRootElementUtil.createPropertyDescriptorMap , which creates the PropertyDescriptorPlus
047: * objects
048: */
049: public class PropertyDescriptorPlus {
050: PropertyDescriptor descriptor;
051: String xmlName = null;
052:
053: private static Log log = LogFactory
054: .getLog(PropertyDescriptorPlus.class);
055: private static final boolean DEBUG_ENABLED = log.isDebugEnabled();
056:
057: /**
058: * Package protected constructor. Only created by XMLRootElementUtil.createPropertyDescriptorMap
059: *
060: * @param propertyName
061: * @param descriptor
062: * @see XMLRootElementUtil.createPropertyDescriptorMap
063: */
064: PropertyDescriptorPlus(PropertyDescriptor descriptor, String xmlName) {
065: super ();
066: this .descriptor = descriptor;
067: this .xmlName = xmlName;
068: }
069:
070: /** @return xmlname */
071: public String getXmlName() {
072: return xmlName;
073: }
074:
075: /** @return property type */
076: public Class getPropertyType() {
077: return descriptor.getPropertyType();
078: }
079:
080: /** @return property name */
081: public String getPropertyName() {
082: return descriptor.getName();
083: }
084:
085: /**
086: * Get the object
087: *
088: * @param targetBean
089: * @return Object for this property or null
090: * @throws InvocationTargetException
091: * @throws IllegalAccessException
092: */
093: public Object get(Object targetBean)
094: throws InvocationTargetException, IllegalAccessException {
095: if (descriptor == null) {
096: if (log.isDebugEnabled()) {
097: log.debug("Null Descriptor");
098: }
099: throw new RuntimeException("PropertyDescriptor not found");
100: }
101: Method method = descriptor.getReadMethod();
102: if (method == null
103: && descriptor.getPropertyType() == Boolean.class) {
104: String propertyName = descriptor.getName();
105: if (propertyName != null) {
106: String methodName = "is";
107: methodName = methodName
108: + ((propertyName.length() > 0) ? propertyName
109: .substring(0, 1).toUpperCase() : "");
110: methodName = methodName
111: + ((propertyName.length() > 1) ? propertyName
112: .substring(1) : "");
113: if (log.isDebugEnabled()) {
114: log.debug("Method Name =" + methodName);
115: }
116: try {
117: method = targetBean.getClass().getMethod(
118: methodName, null);
119: } catch (NoSuchMethodException e) {
120: if (log.isDebugEnabled()) {
121: log.debug("Mehtod not found" + methodName);
122: }
123: }
124: }
125: }
126: if (method == null) {
127: if (log.isDebugEnabled()) {
128: log.debug("No read Method found to read propertyvalue");
129: }
130: throw new RuntimeException(
131: "No read Method found to read property Value from jaxbObject: "
132: + targetBean.getClass().getName());
133: }
134: return method.invoke(targetBean, null);
135: }
136:
137: /**
138: * Set the object
139: *
140: * @param targetBean
141: * @param propValue
142: * @throws InvocationTargetException
143: * @throws IllegalAccessException
144: * @throws JAXBWrapperException
145: */
146: public void set(Object targetBean, Object propValue)
147: throws InvocationTargetException, IllegalAccessException,
148: JAXBWrapperException {
149:
150: // No set occurs if the value is null
151: if (propValue == null) {
152: return;
153: }
154:
155: // There are 3 different types of setters that can occur.
156: // 1) Normal Attomic Setter : setFoo(type)
157: // 2) Indexed Array Setter : setFoo(type[])
158: // 3) No Setter case if the property is a List<T>.
159:
160: Method writeMethod = descriptor.getWriteMethod();
161: if (descriptor instanceof IndexedPropertyDescriptor) {
162: // Set for indexed T[]
163: setIndexedArray(targetBean, propValue, writeMethod);
164: } else if (writeMethod == null) {
165: // Set for List<T>
166: setList(targetBean, propValue);
167: } else {
168: // Normal case
169: setAtomic(targetBean, propValue, writeMethod);
170: }
171: }
172:
173: /**
174: * Set the property value onto targetBean using the writeMethod
175: *
176: * @param targetBean
177: * @param propValue
178: * @param writeMethod (set(T))
179: * @throws InvocationTargetException
180: * @throws IllegalAccessException
181: * @throws JAXBWrapperException
182: */
183: private void setAtomic(Object targetBean, Object propValue,
184: Method writeMethod) throws InvocationTargetException,
185: IllegalAccessException, JAXBWrapperException {
186: // JAXB provides setters for atomic value.
187:
188: if (propValue != null) {
189: // Normal case
190: Object[] SINGLE_PARAM = new Object[1];
191: SINGLE_PARAM[0] = propValue;
192: writeMethod.invoke(targetBean, SINGLE_PARAM);
193: } else {
194: Class[] paramTypes = writeMethod.getParameterTypes();
195:
196: if (paramTypes != null && paramTypes.length == 1) {
197: Class paramType = paramTypes[0];
198: if (paramType.isPrimitive() && propValue == null) {
199: // TODO NLS
200: //Ignoring null value for primitive type, this could potentially be the way of a customer indicating to set
201: //default values defined in JAXBObject/xmlSchema.
202: if (DEBUG_ENABLED) {
203: log
204: .debug("Ignoring null value for primitive type, this is the way to set default values defined in JAXBObject/xmlSchema. for primitive types");
205: }
206: return;
207: }
208: }
209: }
210:
211: }
212:
213: /**
214: * Set the property value using the indexed array setter
215: *
216: * @param targetBean
217: * @param propValue
218: * @param writeMethod set(T[])
219: * @throws InvocationTargetException
220: * @throws IllegalAccessException
221: * @throws JAXBWrapperException
222: */
223: private void setIndexedArray(Object targetBean, Object propValue,
224: Method writeMethod) throws InvocationTargetException,
225: IllegalAccessException, JAXBWrapperException {
226:
227: Class paramType = writeMethod.getParameterTypes()[0];
228: Object value = asArray(propValue, paramType);
229: // JAXB provides setters for atomic value.
230: Object[] SINGLE_PARAM = new Object[1];
231: SINGLE_PARAM[0] = value;
232:
233: writeMethod.invoke(targetBean, SINGLE_PARAM);
234: }
235:
236: /**
237: * Set the property value for the collection case.
238: *
239: * @param targetBean
240: * @param propValue
241: * @throws InvocationTargetException
242: * @throws IllegalAccessException
243: * @throws JAXBWrapperException
244: */
245: private void setList(Object targetBean, Object propValue)
246: throws InvocationTargetException, IllegalAccessException,
247: JAXBWrapperException {
248: // For the List<T> case, there is no setter.
249: // You are supposed to use the getter to obtain access to the collection and then add the collection
250:
251: Collection value = asCollection(propValue, descriptor
252: .getPropertyType());
253: Collection collection = (Collection) get(targetBean);
254:
255: // Now add our our object to the collection
256: collection.clear();
257: if (propValue != null) {
258: collection.addAll(value);
259: }
260: }
261:
262: /**
263: * @param propValue
264: * @param destType
265: * @return propValue as a Collection
266: */
267: private static Collection asCollection(Object propValue,
268: Class destType) {
269: // TODO Missing function
270: // Convert the object into an equivalent object that is a collection
271: if (ConvertUtils.isConvertable(propValue, destType)) {
272: return (Collection) ConvertUtils.convert(propValue,
273: destType);
274: } else {
275: String objectClass = (propValue == null) ? "null"
276: : propValue.getClass().getName();
277: throw ExceptionFactory.makeWebServiceException(Messages
278: .getMessage("convertProblem", objectClass, destType
279: .getName()));
280:
281: }
282: }
283:
284: /**
285: * @param propValue
286: * @param destType T[]
287: * @return array of component type
288: */
289: private static Object asArray(Object propValue, Class destType) {
290: if (ConvertUtils.isConvertable(propValue, destType)) {
291: return ConvertUtils.convert(propValue, destType);
292: } else {
293: String objectClass = (propValue == null) ? "null"
294: : propValue.getClass().getName();
295: throw ExceptionFactory.makeWebServiceException(Messages
296: .getMessage("convertProblem", objectClass, destType
297: .getName()));
298:
299: }
300: }
301:
302: public String toString() {
303: String value = "PropertyDescriptorPlus[";
304: value += " name=" + this .getPropertyName();
305: value += " type=" + this .getPropertyType().getName();
306: value += " propertyDecriptor=" + this .descriptor;
307: return value + "]";
308: }
309: }
|