001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.activemq.util; 018 019import java.math.BigInteger; 020import java.net.URI; 021import java.net.URISyntaxException; 022import java.util.Date; 023import java.util.HashMap; 024import java.util.Map; 025 026import org.apache.activemq.command.ActiveMQDestination; 027import org.fusesource.hawtbuf.UTF8Buffer; 028 029/** 030 * Type conversion support for ActiveMQ. 031 */ 032public final class TypeConversionSupport { 033 034 private static final Converter IDENTITY_CONVERTER = new Converter() { 035 @Override 036 public Object convert(Object value) { 037 return value; 038 } 039 }; 040 041 private static class ConversionKey { 042 final Class<?> from; 043 final Class<?> to; 044 final int hashCode; 045 046 public ConversionKey(Class<?> from, Class<?> to) { 047 this.from = from; 048 this.to = to; 049 this.hashCode = from.hashCode() ^ (to.hashCode() << 1); 050 } 051 052 @Override 053 public boolean equals(Object obj) { 054 if (this == obj) 055 return true; 056 if (obj == null) 057 return false; 058 if (getClass() != obj.getClass()) 059 return false; 060 ConversionKey other = (ConversionKey) obj; 061 if (from == null) { 062 if (other.from != null) 063 return false; 064 } else if (!from.equals(other.from)) 065 return false; 066 if (to == null) { 067 if (other.to != null) 068 return false; 069 } else if (!to.equals(other.to)) 070 return false; 071 return true; 072 } 073 074 @Override 075 public int hashCode() { 076 return hashCode; 077 } 078 } 079 080 public interface Converter { 081 Object convert(Object value); 082 } 083 084 private static final Map<ConversionKey, Converter> CONVERSION_MAP = new HashMap<ConversionKey, Converter>(); 085 static { 086 Converter toStringConverter = new Converter() { 087 @Override 088 public Object convert(Object value) { 089 return value.toString(); 090 } 091 }; 092 CONVERSION_MAP.put(new ConversionKey(Boolean.class, String.class), toStringConverter); 093 CONVERSION_MAP.put(new ConversionKey(Byte.class, String.class), toStringConverter); 094 CONVERSION_MAP.put(new ConversionKey(Short.class, String.class), toStringConverter); 095 CONVERSION_MAP.put(new ConversionKey(Integer.class, String.class), toStringConverter); 096 CONVERSION_MAP.put(new ConversionKey(Long.class, String.class), toStringConverter); 097 CONVERSION_MAP.put(new ConversionKey(Float.class, String.class), toStringConverter); 098 CONVERSION_MAP.put(new ConversionKey(Double.class, String.class), toStringConverter); 099 CONVERSION_MAP.put(new ConversionKey(UTF8Buffer.class, String.class), toStringConverter); 100 CONVERSION_MAP.put(new ConversionKey(URI.class, String.class), toStringConverter); 101 CONVERSION_MAP.put(new ConversionKey(BigInteger.class, String.class), toStringConverter); 102 103 CONVERSION_MAP.put(new ConversionKey(String.class, Boolean.class), new Converter() { 104 @Override 105 public Object convert(Object value) { 106 return Boolean.valueOf((String)value); 107 } 108 }); 109 CONVERSION_MAP.put(new ConversionKey(String.class, Byte.class), new Converter() { 110 @Override 111 public Object convert(Object value) { 112 return Byte.valueOf((String)value); 113 } 114 }); 115 CONVERSION_MAP.put(new ConversionKey(String.class, Short.class), new Converter() { 116 @Override 117 public Object convert(Object value) { 118 return Short.valueOf((String)value); 119 } 120 }); 121 CONVERSION_MAP.put(new ConversionKey(String.class, Integer.class), new Converter() { 122 @Override 123 public Object convert(Object value) { 124 return Integer.valueOf((String)value); 125 } 126 }); 127 CONVERSION_MAP.put(new ConversionKey(String.class, Long.class), new Converter() { 128 @Override 129 public Object convert(Object value) { 130 return Long.valueOf((String)value); 131 } 132 }); 133 CONVERSION_MAP.put(new ConversionKey(String.class, Float.class), new Converter() { 134 @Override 135 public Object convert(Object value) { 136 return Float.valueOf((String)value); 137 } 138 }); 139 CONVERSION_MAP.put(new ConversionKey(String.class, Double.class), new Converter() { 140 @Override 141 public Object convert(Object value) { 142 return Double.valueOf((String)value); 143 } 144 }); 145 146 Converter longConverter = new Converter() { 147 @Override 148 public Object convert(Object value) { 149 return Long.valueOf(((Number)value).longValue()); 150 } 151 }; 152 CONVERSION_MAP.put(new ConversionKey(Byte.class, Long.class), longConverter); 153 CONVERSION_MAP.put(new ConversionKey(Short.class, Long.class), longConverter); 154 CONVERSION_MAP.put(new ConversionKey(Integer.class, Long.class), longConverter); 155 CONVERSION_MAP.put(new ConversionKey(Date.class, Long.class), new Converter() { 156 @Override 157 public Object convert(Object value) { 158 return Long.valueOf(((Date)value).getTime()); 159 } 160 }); 161 162 Converter intConverter = new Converter() { 163 @Override 164 public Object convert(Object value) { 165 return Integer.valueOf(((Number)value).intValue()); 166 } 167 }; 168 CONVERSION_MAP.put(new ConversionKey(Byte.class, Integer.class), intConverter); 169 CONVERSION_MAP.put(new ConversionKey(Short.class, Integer.class), intConverter); 170 171 CONVERSION_MAP.put(new ConversionKey(Byte.class, Short.class), new Converter() { 172 @Override 173 public Object convert(Object value) { 174 return Short.valueOf(((Number)value).shortValue()); 175 } 176 }); 177 178 CONVERSION_MAP.put(new ConversionKey(Float.class, Double.class), new Converter() { 179 @Override 180 public Object convert(Object value) { 181 return new Double(((Number)value).doubleValue()); 182 } 183 }); 184 CONVERSION_MAP.put(new ConversionKey(String.class, ActiveMQDestination.class), new Converter() { 185 @Override 186 public Object convert(Object value) { 187 return ActiveMQDestination.createDestination((String)value, ActiveMQDestination.QUEUE_TYPE); 188 } 189 }); 190 CONVERSION_MAP.put(new ConversionKey(String.class, URI.class), new Converter() { 191 @Override 192 public Object convert(Object value) { 193 String text = value.toString(); 194 try { 195 return new URI(text); 196 } catch (URISyntaxException e) { 197 throw new RuntimeException(e); 198 } 199 } 200 }); 201 } 202 203 private TypeConversionSupport() { 204 } 205 206 public static Object convert(Object value, Class<?> to) { 207 if (value == null) { 208 // lets avoid NullPointerException when converting to boolean for null values 209 if (boolean.class.isAssignableFrom(to)) { 210 return Boolean.FALSE; 211 } 212 return null; 213 } 214 215 // eager same instance type test to avoid the overhead of invoking the type converter 216 // if already same type 217 if (to.isInstance(value)) { 218 return to.cast(value); 219 } 220 221 // lookup converter 222 Converter c = lookupConverter(value.getClass(), to); 223 if (c != null) { 224 return c.convert(value); 225 } else { 226 return null; 227 } 228 } 229 230 public static Converter lookupConverter(Class<?> from, Class<?> to) { 231 // use wrapped type for primitives 232 if (from.isPrimitive()) { 233 from = convertPrimitiveTypeToWrapperType(from); 234 } 235 if (to.isPrimitive()) { 236 to = convertPrimitiveTypeToWrapperType(to); 237 } 238 239 if (from.equals(to)) { 240 return IDENTITY_CONVERTER; 241 } 242 243 return CONVERSION_MAP.get(new ConversionKey(from, to)); 244 } 245 246 /** 247 * Converts primitive types such as int to its wrapper type like 248 * {@link Integer} 249 */ 250 private static Class<?> convertPrimitiveTypeToWrapperType(Class<?> type) { 251 Class<?> rc = type; 252 if (type.isPrimitive()) { 253 if (type == int.class) { 254 rc = Integer.class; 255 } else if (type == long.class) { 256 rc = Long.class; 257 } else if (type == double.class) { 258 rc = Double.class; 259 } else if (type == float.class) { 260 rc = Float.class; 261 } else if (type == short.class) { 262 rc = Short.class; 263 } else if (type == byte.class) { 264 rc = Byte.class; 265 } else if (type == boolean.class) { 266 rc = Boolean.class; 267 } 268 } 269 return rc; 270 } 271}