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 o) { 054 ConversionKey x = (ConversionKey)o; 055 return x.from == from && x.to == to; 056 } 057 058 @Override 059 public int hashCode() { 060 return hashCode; 061 } 062 } 063 064 public interface Converter { 065 Object convert(Object value); 066 } 067 068 private static final Map<ConversionKey, Converter> CONVERSION_MAP = new HashMap<ConversionKey, Converter>(); 069 static { 070 Converter toStringConverter = new Converter() { 071 @Override 072 public Object convert(Object value) { 073 return value.toString(); 074 } 075 }; 076 CONVERSION_MAP.put(new ConversionKey(Boolean.class, String.class), toStringConverter); 077 CONVERSION_MAP.put(new ConversionKey(Byte.class, String.class), toStringConverter); 078 CONVERSION_MAP.put(new ConversionKey(Short.class, String.class), toStringConverter); 079 CONVERSION_MAP.put(new ConversionKey(Integer.class, String.class), toStringConverter); 080 CONVERSION_MAP.put(new ConversionKey(Long.class, String.class), toStringConverter); 081 CONVERSION_MAP.put(new ConversionKey(Float.class, String.class), toStringConverter); 082 CONVERSION_MAP.put(new ConversionKey(Double.class, String.class), toStringConverter); 083 CONVERSION_MAP.put(new ConversionKey(UTF8Buffer.class, String.class), toStringConverter); 084 CONVERSION_MAP.put(new ConversionKey(URI.class, String.class), toStringConverter); 085 CONVERSION_MAP.put(new ConversionKey(BigInteger.class, String.class), toStringConverter); 086 087 CONVERSION_MAP.put(new ConversionKey(String.class, Boolean.class), new Converter() { 088 @Override 089 public Object convert(Object value) { 090 return Boolean.valueOf((String)value); 091 } 092 }); 093 CONVERSION_MAP.put(new ConversionKey(String.class, Byte.class), new Converter() { 094 @Override 095 public Object convert(Object value) { 096 return Byte.valueOf((String)value); 097 } 098 }); 099 CONVERSION_MAP.put(new ConversionKey(String.class, Short.class), new Converter() { 100 @Override 101 public Object convert(Object value) { 102 return Short.valueOf((String)value); 103 } 104 }); 105 CONVERSION_MAP.put(new ConversionKey(String.class, Integer.class), new Converter() { 106 @Override 107 public Object convert(Object value) { 108 return Integer.valueOf((String)value); 109 } 110 }); 111 CONVERSION_MAP.put(new ConversionKey(String.class, Long.class), new Converter() { 112 @Override 113 public Object convert(Object value) { 114 return Long.valueOf((String)value); 115 } 116 }); 117 CONVERSION_MAP.put(new ConversionKey(String.class, Float.class), new Converter() { 118 @Override 119 public Object convert(Object value) { 120 return Float.valueOf((String)value); 121 } 122 }); 123 CONVERSION_MAP.put(new ConversionKey(String.class, Double.class), new Converter() { 124 @Override 125 public Object convert(Object value) { 126 return Double.valueOf((String)value); 127 } 128 }); 129 130 Converter longConverter = new Converter() { 131 @Override 132 public Object convert(Object value) { 133 return Long.valueOf(((Number)value).longValue()); 134 } 135 }; 136 CONVERSION_MAP.put(new ConversionKey(Byte.class, Long.class), longConverter); 137 CONVERSION_MAP.put(new ConversionKey(Short.class, Long.class), longConverter); 138 CONVERSION_MAP.put(new ConversionKey(Integer.class, Long.class), longConverter); 139 CONVERSION_MAP.put(new ConversionKey(Date.class, Long.class), new Converter() { 140 @Override 141 public Object convert(Object value) { 142 return Long.valueOf(((Date)value).getTime()); 143 } 144 }); 145 146 Converter intConverter = new Converter() { 147 @Override 148 public Object convert(Object value) { 149 return Integer.valueOf(((Number)value).intValue()); 150 } 151 }; 152 CONVERSION_MAP.put(new ConversionKey(Byte.class, Integer.class), intConverter); 153 CONVERSION_MAP.put(new ConversionKey(Short.class, Integer.class), intConverter); 154 155 CONVERSION_MAP.put(new ConversionKey(Byte.class, Short.class), new Converter() { 156 @Override 157 public Object convert(Object value) { 158 return Short.valueOf(((Number)value).shortValue()); 159 } 160 }); 161 162 CONVERSION_MAP.put(new ConversionKey(Float.class, Double.class), new Converter() { 163 @Override 164 public Object convert(Object value) { 165 return new Double(((Number)value).doubleValue()); 166 } 167 }); 168 CONVERSION_MAP.put(new ConversionKey(String.class, ActiveMQDestination.class), new Converter() { 169 @Override 170 public Object convert(Object value) { 171 return ActiveMQDestination.createDestination((String)value, ActiveMQDestination.QUEUE_TYPE); 172 } 173 }); 174 CONVERSION_MAP.put(new ConversionKey(String.class, URI.class), new Converter() { 175 @Override 176 public Object convert(Object value) { 177 String text = value.toString(); 178 try { 179 return new URI(text); 180 } catch (URISyntaxException e) { 181 throw new RuntimeException(e); 182 } 183 } 184 }); 185 } 186 187 private TypeConversionSupport() { 188 } 189 190 public static Object convert(Object value, Class<?> to) { 191 if (value == null) { 192 // lets avoid NullPointerException when converting to boolean for null values 193 if (boolean.class.isAssignableFrom(to)) { 194 return Boolean.FALSE; 195 } 196 return null; 197 } 198 199 // eager same instance type test to avoid the overhead of invoking the type converter 200 // if already same type 201 if (to.isInstance(value)) { 202 return to.cast(value); 203 } 204 205 // lookup converter 206 Converter c = lookupConverter(value.getClass(), to); 207 if (c != null) { 208 return c.convert(value); 209 } else { 210 return null; 211 } 212 } 213 214 public static Converter lookupConverter(Class<?> from, Class<?> to) { 215 // use wrapped type for primitives 216 if (from.isPrimitive()) { 217 from = convertPrimitiveTypeToWrapperType(from); 218 } 219 if (to.isPrimitive()) { 220 to = convertPrimitiveTypeToWrapperType(to); 221 } 222 223 if (from.equals(to)) { 224 return IDENTITY_CONVERTER; 225 } 226 227 return CONVERSION_MAP.get(new ConversionKey(from, to)); 228 } 229 230 /** 231 * Converts primitive types such as int to its wrapper type like 232 * {@link Integer} 233 */ 234 private static Class<?> convertPrimitiveTypeToWrapperType(Class<?> type) { 235 Class<?> rc = type; 236 if (type.isPrimitive()) { 237 if (type == int.class) { 238 rc = Integer.class; 239 } else if (type == long.class) { 240 rc = Long.class; 241 } else if (type == double.class) { 242 rc = Double.class; 243 } else if (type == float.class) { 244 rc = Float.class; 245 } else if (type == short.class) { 246 rc = Short.class; 247 } else if (type == byte.class) { 248 rc = Byte.class; 249 } else if (type == boolean.class) { 250 rc = Boolean.class; 251 } 252 } 253 return rc; 254 } 255}