| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package org.apache.axis2.jaxws.utility; |
| |
| import org.apache.axis2.jaxws.ExceptionFactory; |
| import org.apache.axis2.jaxws.i18n.Messages; |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| |
| import javax.activation.DataHandler; |
| import javax.imageio.ImageIO; |
| import javax.xml.transform.Result; |
| import javax.xml.transform.Source; |
| import javax.xml.transform.Transformer; |
| import javax.xml.transform.TransformerFactory; |
| import javax.xml.transform.stream.StreamResult; |
| import javax.xml.transform.stream.StreamSource; |
| import javax.xml.ws.WebServiceException; |
| import java.awt.*; |
| import java.io.ByteArrayOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.lang.reflect.Array; |
| import java.util.ArrayList; |
| import java.util.Calendar; |
| import java.util.Collection; |
| import java.util.Date; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Hashtable; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Set; |
| |
| /** |
| * Provides utilities to convert an object into a different kind of Object. For example, convert a |
| * String[] into a List<String> |
| */ |
| public class ConvertUtils { |
| |
| private static final Log log = LogFactory.getLog(ConvertUtils.class); |
| |
| /** |
| * This method should return true if the convert method will succeed. |
| * <p/> |
| * Note that any changes to isConvertable() must also be accompanied by similar changes to |
| * convert() |
| * |
| * @param obj source object or class |
| * @param dest destination class |
| * @return boolean true if convert(..) can convert obj to the destination class |
| */ |
| public static boolean isConvertable(Object obj, Class dest) { |
| Class src = null; |
| |
| if (obj != null) { |
| if (obj instanceof Class) { |
| src = (Class)obj; |
| } else { |
| src = obj.getClass(); |
| } |
| } |
| |
| if (dest == null) { |
| return false; |
| } |
| |
| if (src == null) { |
| return true; |
| } |
| |
| // If we're directly assignable, we're good. |
| if (dest.isAssignableFrom(src)) { |
| return true; |
| } |
| |
| // If it's a wrapping conversion, we're good. |
| if (JavaUtils.getWrapperClass(src) == dest) { |
| return true; |
| } |
| if (JavaUtils.getWrapperClass(dest) == src) { |
| return true; |
| } |
| |
| // If it's List -> Array or vice versa, we're good. |
| if ((Collection.class.isAssignableFrom(src) || src.isArray()) && |
| (Collection.class.isAssignableFrom(dest) || dest.isArray())) { |
| |
| // TODO this should consider the component types instead of returning true. |
| return true; |
| } |
| |
| // Allow mapping of HashMaps to Hashtables |
| if (src == HashMap.class && dest == Hashtable.class) |
| return true; |
| |
| // Allow mapping of Calendar to Date |
| if (Calendar.class.isAssignableFrom(src) && dest == Date.class) { |
| return true; |
| } |
| |
| if (src.isPrimitive()) { |
| return isConvertable(JavaUtils.getWrapperClass(src), dest); |
| } |
| |
| if (InputStream.class.isAssignableFrom(src) && dest == byte[].class) { |
| return true; |
| } |
| |
| if (Source.class.isAssignableFrom(src) && dest == byte[].class) { |
| return true; |
| } |
| |
| if (DataHandler.class.isAssignableFrom(src) && isConvertable(byte[].class, dest)) { |
| return true; |
| } |
| |
| if (DataHandler.class.isAssignableFrom(src) && dest == Image.class) { |
| return true; |
| } |
| |
| if (DataHandler.class.isAssignableFrom(src) && dest == Source.class) { |
| return true; |
| } |
| |
| if (byte[].class.isAssignableFrom(src) && dest == String.class) { |
| return true; |
| } |
| |
| // If it's a MIME type mapping and we want a DataHandler, |
| // then we're good. |
| // REVIEW Do we want to support this |
| /* |
| if (dest.getName().equals("javax.activation.DataHandler")) { |
| String name = src.getName(); |
| if (src == String.class |
| || src == java.awt.Image.class |
| || name.equals("javax.mail.internet.MimeMultipart") |
| || name.equals("javax.xml.transform.Source")) |
| return true; |
| } |
| */ |
| |
| |
| return false; |
| } |
| |
| /** |
| * Utility function to convert an Object to some desired Class. |
| * <p/> |
| * Normally this is used for T[] to List<T> processing. Other conversions are also done (i.e. |
| * HashMap <->Hashtable, etc.) |
| * <p/> |
| * Use the isConvertable() method to determine if conversion is possible. Note that any changes |
| * to convert() must also be accompanied by similar changes to isConvertable() |
| * |
| * @param arg the array to convert |
| * @param destClass the actual class we want |
| * @return object of destClass if conversion possible, otherwise returns arg |
| */ |
| public static Object convert(Object arg, Class destClass) throws WebServiceException { |
| if (destClass == null) { |
| return arg; |
| } |
| |
| if (arg != null && destClass.isAssignableFrom(arg.getClass())) { |
| return arg; |
| } |
| |
| if (log.isDebugEnabled()) { |
| String clsName = "null"; |
| if (arg != null) clsName = arg.getClass().getName(); |
| log.debug("Converting an object of type " + clsName + " to an object of type " + |
| destClass.getName()); |
| } |
| |
| // Convert between Calendar and Date |
| if (arg instanceof Calendar && destClass == Date.class) { |
| return ((Calendar)arg).getTime(); |
| } |
| |
| // Convert between HashMap and Hashtable |
| if (arg instanceof HashMap && destClass == Hashtable.class) { |
| return new Hashtable((HashMap)arg); |
| } |
| |
| if (arg instanceof InputStream && destClass == byte[].class) { |
| |
| try { |
| InputStream is = (InputStream) arg; |
| return getBytesFromStream(is); |
| } catch (IOException e) { |
| throw ExceptionFactory.makeWebServiceException(e); |
| } |
| } |
| |
| if (arg instanceof Source && destClass == byte[].class) { |
| try { |
| if (arg instanceof StreamSource) { |
| InputStream is = ((StreamSource) arg).getInputStream(); |
| if (is != null) { |
| return getBytesFromStream(is); |
| } |
| } |
| ByteArrayOutputStream out = new ByteArrayOutputStream(); |
| Result result = new StreamResult(out); |
| Transformer transformer = TransformerFactory.newInstance().newTransformer(); |
| transformer.transform((Source) arg, result); |
| byte[] bytes = out.toByteArray(); |
| return bytes; |
| |
| } catch (Exception e) { |
| throw ExceptionFactory.makeWebServiceException(e); |
| } |
| } |
| |
| |
| if (arg instanceof DataHandler) { |
| try { |
| InputStream is = ((DataHandler) arg).getInputStream(); |
| if (destClass == Image.class) { |
| return ImageIO.read(is); |
| } else if (destClass == Source.class) { |
| return new StreamSource(is); |
| } |
| byte[] bytes = getBytesFromStream(is); |
| return convert(bytes, destClass); |
| } catch (Exception e) { |
| throw ExceptionFactory.makeWebServiceException(e); |
| } |
| } |
| |
| if (arg instanceof byte[] && destClass == String.class) { |
| return new String((byte[]) arg); |
| } |
| |
| // If the destination is an array and the source |
| // is a suitable component, return an array with |
| // the single item. |
| /* REVIEW do we need to support atomic to array conversion ? |
| if (arg != null && |
| destClass.isArray() && |
| !destClass.getComponentType().equals(Object.class) && |
| destClass.getComponentType().isAssignableFrom(arg.getClass())) { |
| Object array = |
| Array.newInstance(destClass.getComponentType(), 1); |
| Array.set(array, 0, arg); |
| return array; |
| } |
| */ |
| |
| // Return if no conversion is available |
| if (!(arg instanceof Collection || |
| (arg != null && arg.getClass().isArray()))) { |
| return arg; |
| } |
| |
| if (arg == null) { |
| return null; |
| } |
| |
| // The arg may be an array or List |
| Object destValue = null; |
| int length = 0; |
| if (arg.getClass().isArray()) { |
| length = Array.getLength(arg); |
| } else { |
| length = ((Collection)arg).size(); |
| } |
| |
| try { |
| if (destClass.isArray()) { |
| if (destClass.getComponentType().isPrimitive()) { |
| |
| Object array = Array.newInstance(destClass.getComponentType(), |
| length); |
| // Assign array elements |
| if (arg.getClass().isArray()) { |
| for (int i = 0; i < length; i++) { |
| Array.set(array, i, Array.get(arg, i)); |
| } |
| } else { |
| int idx = 0; |
| for (Iterator i = ((Collection)arg).iterator(); |
| i.hasNext();) { |
| Array.set(array, idx++, i.next()); |
| } |
| } |
| destValue = array; |
| |
| } else { |
| Object [] array; |
| try { |
| array = (Object [])Array.newInstance(destClass.getComponentType(), |
| length); |
| } catch (Exception e) { |
| return arg; |
| } |
| |
| // Use convert to assign array elements. |
| if (arg.getClass().isArray()) { |
| for (int i = 0; i < length; i++) { |
| array[i] = convert(Array.get(arg, i), |
| destClass.getComponentType()); |
| } |
| } else { |
| int idx = 0; |
| for (Iterator i = ((Collection)arg).iterator(); |
| i.hasNext();) { |
| array[idx++] = convert(i.next(), |
| destClass.getComponentType()); |
| } |
| } |
| destValue = array; |
| } |
| } else if (Collection.class.isAssignableFrom(destClass)) { |
| Collection newList = null; |
| try { |
| // if we are trying to create an interface, build something |
| // that implements the interface |
| if (destClass == Collection.class || destClass == List.class) { |
| newList = new ArrayList(); |
| } else if (destClass == Set.class) { |
| newList = new HashSet(); |
| } else { |
| newList = (Collection)destClass.newInstance(); |
| } |
| } catch (Exception e) { |
| // No FFDC code needed |
| // Couldn't build one for some reason... so forget it. |
| return arg; |
| } |
| |
| if (arg.getClass().isArray()) { |
| for (int j = 0; j < length; j++) { |
| newList.add(Array.get(arg, j)); |
| } |
| } else { |
| for (Iterator j = ((Collection)arg).iterator(); |
| j.hasNext();) { |
| newList.add(j.next()); |
| } |
| } |
| destValue = newList; |
| } else { |
| destValue = arg; |
| } |
| } catch (Throwable t) { |
| throw ExceptionFactory. |
| makeWebServiceException( |
| Messages.getMessage("convertUtils", |
| arg.getClass().toString(), |
| destClass.toString()), |
| t); |
| } |
| |
| return destValue; |
| } |
| |
| private static byte[] getBytesFromStream(InputStream is) throws IOException { |
| // TODO This code assumes that available is the length of the stream. |
| byte[] bytes = new byte[is.available()]; |
| is.read(bytes); |
| return bytes; |
| } |
| } |