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 */
017 package org.apache.activemq.util;
018
019 import java.net.URI;
020 import java.net.URISyntaxException;
021 import java.util.Date;
022 import java.util.HashMap;
023 import java.util.Map;
024
025 import org.apache.activemq.command.ActiveMQDestination;
026
027 /**
028 * Type conversion support for ActiveMQ.
029 */
030 public final class TypeConversionSupport {
031
032 private static class ConversionKey {
033 final Class from;
034 final Class to;
035 final int hashCode;
036
037 public ConversionKey(Class from, Class to) {
038 this.from = from;
039 this.to = to;
040 this.hashCode = from.hashCode() ^ (to.hashCode() << 1);
041 }
042
043 public boolean equals(Object o) {
044 ConversionKey x = (ConversionKey)o;
045 return x.from == from && x.to == to;
046 }
047
048 public int hashCode() {
049 return hashCode;
050 }
051 }
052
053 public interface Converter {
054 Object convert(Object value);
055 }
056
057 private static final Map<ConversionKey, Converter> CONVERSION_MAP = new HashMap<ConversionKey, Converter>();
058 static {
059 Converter toStringConverter = new Converter() {
060 public Object convert(Object value) {
061 return value.toString();
062 }
063 };
064 CONVERSION_MAP.put(new ConversionKey(Boolean.class, String.class), toStringConverter);
065 CONVERSION_MAP.put(new ConversionKey(Byte.class, String.class), toStringConverter);
066 CONVERSION_MAP.put(new ConversionKey(Short.class, String.class), toStringConverter);
067 CONVERSION_MAP.put(new ConversionKey(Integer.class, String.class), toStringConverter);
068 CONVERSION_MAP.put(new ConversionKey(Long.class, String.class), toStringConverter);
069 CONVERSION_MAP.put(new ConversionKey(Float.class, String.class), toStringConverter);
070 CONVERSION_MAP.put(new ConversionKey(Double.class, String.class), toStringConverter);
071
072 CONVERSION_MAP.put(new ConversionKey(String.class, Boolean.class), new Converter() {
073 public Object convert(Object value) {
074 return Boolean.valueOf((String)value);
075 }
076 });
077 CONVERSION_MAP.put(new ConversionKey(String.class, Byte.class), new Converter() {
078 public Object convert(Object value) {
079 return Byte.valueOf((String)value);
080 }
081 });
082 CONVERSION_MAP.put(new ConversionKey(String.class, Short.class), new Converter() {
083 public Object convert(Object value) {
084 return Short.valueOf((String)value);
085 }
086 });
087 CONVERSION_MAP.put(new ConversionKey(String.class, Integer.class), new Converter() {
088 public Object convert(Object value) {
089 return Integer.valueOf((String)value);
090 }
091 });
092 CONVERSION_MAP.put(new ConversionKey(String.class, Long.class), new Converter() {
093 public Object convert(Object value) {
094 return Long.valueOf((String)value);
095 }
096 });
097 CONVERSION_MAP.put(new ConversionKey(String.class, Float.class), new Converter() {
098 public Object convert(Object value) {
099 return Float.valueOf((String)value);
100 }
101 });
102 CONVERSION_MAP.put(new ConversionKey(String.class, Double.class), new Converter() {
103 public Object convert(Object value) {
104 return Double.valueOf((String)value);
105 }
106 });
107
108 Converter longConverter = new Converter() {
109 public Object convert(Object value) {
110 return Long.valueOf(((Number)value).longValue());
111 }
112 };
113 CONVERSION_MAP.put(new ConversionKey(Byte.class, Long.class), longConverter);
114 CONVERSION_MAP.put(new ConversionKey(Short.class, Long.class), longConverter);
115 CONVERSION_MAP.put(new ConversionKey(Integer.class, Long.class), longConverter);
116 CONVERSION_MAP.put(new ConversionKey(Date.class, Long.class), new Converter() {
117 public Object convert(Object value) {
118 return Long.valueOf(((Date)value).getTime());
119 }
120 });
121
122 Converter intConverter = new Converter() {
123 public Object convert(Object value) {
124 return Integer.valueOf(((Number)value).intValue());
125 }
126 };
127 CONVERSION_MAP.put(new ConversionKey(Byte.class, Integer.class), intConverter);
128 CONVERSION_MAP.put(new ConversionKey(Short.class, Integer.class), intConverter);
129
130 CONVERSION_MAP.put(new ConversionKey(Byte.class, Short.class), new Converter() {
131 public Object convert(Object value) {
132 return Short.valueOf(((Number)value).shortValue());
133 }
134 });
135
136 CONVERSION_MAP.put(new ConversionKey(Float.class, Double.class), new Converter() {
137 public Object convert(Object value) {
138 return new Double(((Number)value).doubleValue());
139 }
140 });
141 CONVERSION_MAP.put(new ConversionKey(String.class, ActiveMQDestination.class), new Converter() {
142 public Object convert(Object value) {
143 return ActiveMQDestination.createDestination((String)value, ActiveMQDestination.QUEUE_TYPE);
144 }
145 });
146 CONVERSION_MAP.put(new ConversionKey(String.class, URI.class), new Converter() {
147 public Object convert(Object value) {
148 String text = value.toString();
149 try {
150 return new URI(text);
151 } catch (URISyntaxException e) {
152 throw new RuntimeException(e);
153 }
154 }
155 });
156 }
157
158 private TypeConversionSupport() {
159 }
160
161 public static Object convert(Object value, Class to) {
162 if (value == null) {
163 // lets avoid NullPointerException when converting to boolean for null values
164 if (boolean.class.isAssignableFrom(to)) {
165 return Boolean.FALSE;
166 }
167 return null;
168 }
169
170 // eager same instance type test to avoid the overhead of invoking the type converter
171 // if already same type
172 if (to.isInstance(value)) {
173 return to.cast(value);
174 }
175
176 // lookup converter
177 Converter c = lookupConverter(value.getClass(), to);
178 if (c != null) {
179 return c.convert(value);
180 } else {
181 return null;
182 }
183 }
184
185 public static Converter lookupConverter(Class from, Class to) {
186 // use wrapped type for primitives
187 if (from.isPrimitive()) {
188 from = convertPrimitiveTypeToWrapperType(from);
189 }
190 if (to.isPrimitive()) {
191 to = convertPrimitiveTypeToWrapperType(to);
192 }
193
194 return CONVERSION_MAP.get(new ConversionKey(from, to));
195 }
196
197 /**
198 * Converts primitive types such as int to its wrapper type like
199 * {@link Integer}
200 */
201 private static Class<?> convertPrimitiveTypeToWrapperType(Class<?> type) {
202 Class<?> rc = type;
203 if (type.isPrimitive()) {
204 if (type == int.class) {
205 rc = Integer.class;
206 } else if (type == long.class) {
207 rc = Long.class;
208 } else if (type == double.class) {
209 rc = Double.class;
210 } else if (type == float.class) {
211 rc = Float.class;
212 } else if (type == short.class) {
213 rc = Short.class;
214 } else if (type == byte.class) {
215 rc = Byte.class;
216 } else if (type == boolean.class) {
217 rc = Boolean.class;
218 }
219 }
220 return rc;
221 }
222
223 }