diff --git a/activemq-core/src/main/java/org/apache/activemq/util/BooleanEditor.java b/activemq-core/src/main/java/org/apache/activemq/util/BooleanEditor.java
index d96079343d..065affd038 100644
--- a/activemq-core/src/main/java/org/apache/activemq/util/BooleanEditor.java
+++ b/activemq-core/src/main/java/org/apache/activemq/util/BooleanEditor.java
@@ -18,7 +18,12 @@ package org.apache.activemq.util;
import java.beans.PropertyEditorSupport;
-@Deprecated
+/**
+ * Used by xbean to set booleans.
+ *
+ * Important: Do not use this for other purposes than xbean, as property editors
+ * are not thread safe, and they are slow to use.
+ */
public class BooleanEditor extends PropertyEditorSupport {
public String getJavaInitializationString() {
diff --git a/activemq-core/src/main/java/org/apache/activemq/util/IntrospectionSupport.java b/activemq-core/src/main/java/org/apache/activemq/util/IntrospectionSupport.java
index 7a2eee06ab..ef38c353e7 100755
--- a/activemq-core/src/main/java/org/apache/activemq/util/IntrospectionSupport.java
+++ b/activemq-core/src/main/java/org/apache/activemq/util/IntrospectionSupport.java
@@ -16,12 +16,9 @@
*/
package org.apache.activemq.util;
-import java.beans.PropertyEditor;
-import java.beans.PropertyEditorManager;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
@@ -34,34 +31,13 @@ import java.util.Set;
import javax.net.ssl.SSLServerSocket;
import org.apache.activemq.command.ActiveMQDestination;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public final class IntrospectionSupport {
-
- static {
- // Add Spring and ActiveMQ specific property editors
- String[] additionalPath = new String[] {
- "org.springframework.beans.propertyeditors",
- "org.apache.activemq.util" };
- synchronized (PropertyEditorManager.class) {
- List list = new ArrayList();
- list.addAll(Arrays.asList(PropertyEditorManager.getEditorSearchPath()));
- if (!list.contains(additionalPath[0])) {
- list.add(additionalPath[0]);
- }
- if (!list.contains(additionalPath[1])) {
- list.add(additionalPath[1]);
- }
+ private static final Logger LOG = LoggerFactory.getLogger(IntrospectionSupport.class);
- String[] newSearchPath = list.toArray(new String[list.size()]);
- try {
- PropertyEditorManager.setEditorSearchPath(newSearchPath);
- } catch(java.security.AccessControlException ignore) {
- // we might be in an applet...
- }
- }
- }
-
private IntrospectionSupport() {
}
@@ -86,7 +62,7 @@ public final class IntrospectionSupport {
String name = method.getName();
Class type = method.getReturnType();
Class params[] = method.getParameterTypes();
- if ((name.startsWith("is") || name.startsWith("get")) && params.length == 0 && type != null && isSettableType(type)) {
+ if ((name.startsWith("is") || name.startsWith("get")) && params.length == 0 && type != null) {
try {
@@ -208,33 +184,75 @@ public final class IntrospectionSupport {
}
}
- private static Object convert(Object value, Class type) {
+ private static Object convert(Object value, Class to) {
+ if (value == null) {
+ // lets avoid NullPointerException when converting to boolean for null values
+ if (boolean.class.isAssignableFrom(to)) {
+ return Boolean.FALSE;
+ }
+ return null;
+ }
+
+ // eager same instance type test to avoid the overhead of invoking the type converter
+ // if already same type
+ if (to.isAssignableFrom(value.getClass())) {
+ return to.cast(value);
+ }
+
// special for String[] as we do not want to use a PropertyEditor for that
- if (type.isAssignableFrom(String[].class)) {
+ if (to.isAssignableFrom(String[].class)) {
return StringArrayConverter.convertToStringArray(value);
}
- PropertyEditor editor = PropertyEditorManager.findEditor(type);
- if (editor != null) {
- editor.setAsText(value.toString());
- return editor.getValue();
+ // special for String to List as we do not want to use a PropertyEditor for that
+ if (value.getClass().equals(String.class) && to.equals(List.class)) {
+ Object answer = StringToListOfActiveMQDestinationConverter.convertToActiveMQDestination(value);
+ if (answer != null) {
+ return answer;
+ }
+ }
+
+ TypeConversionSupport.Converter converter = TypeConversionSupport.lookupConverter(value.getClass(), to);
+ if (converter != null) {
+ return converter.convert(value);
+ } else {
+ throw new IllegalArgumentException("Cannot convert from " + value.getClass()
+ + " to " + to + " with value " + value);
}
- return null;
}
- public static String convertToString(Object value, Class type) {
+ public static String convertToString(Object value, Class to) {
+ if (value == null) {
+ return null;
+ }
+
+ // already a String
+ if (value instanceof String) {
+ return (String) value;
+ }
+
// special for String[] as we do not want to use a PropertyEditor for that
- if (value != null && value.getClass().isAssignableFrom(String[].class)) {
+ if (String[].class.isInstance(value)) {
String[] array = (String[]) value;
return StringArrayConverter.convertToString(array);
}
- PropertyEditor editor = PropertyEditorManager.findEditor(type);
- if (editor != null) {
- editor.setValue(value);
- return editor.getAsText();
+ // special for String to List as we do not want to use a PropertyEditor for that
+ if (List.class.isInstance(value)) {
+ // if the list is a ActiveMQDestination, then return a comma list
+ String answer = StringToListOfActiveMQDestinationConverter.convertFromActiveMQDestination(value);
+ if (answer != null) {
+ return answer;
+ }
+ }
+
+ TypeConversionSupport.Converter converter = TypeConversionSupport.lookupConverter(value.getClass(), String.class);
+ if (converter != null) {
+ return (String) converter.convert(value);
+ } else {
+ throw new IllegalArgumentException("Cannot convert from " + value.getClass()
+ + " to " + to + " with value " + value);
}
- return null;
}
private static Method findSetterMethod(Class clazz, String name) {
@@ -251,19 +269,6 @@ public final class IntrospectionSupport {
return null;
}
- private static boolean isSettableType(Class clazz) {
- // special for String[]
- if (clazz.isAssignableFrom(String[].class)) {
- return true;
- }
-
- if (PropertyEditorManager.findEditor(clazz) != null) {
- return true;
- }
-
- return false;
- }
-
public static String toString(Object target) {
return toString(target, Object.class, null);
}
@@ -349,7 +354,7 @@ public final class IntrospectionSupport {
}
map.put(field.getName(), o);
} catch (Throwable e) {
- e.printStackTrace();
+ LOG.debug("Error getting field " + field + " on class " + startClass + ". This exception is ignored.", e);
}
}
diff --git a/activemq-core/src/main/java/org/apache/activemq/util/ListEditor.java b/activemq-core/src/main/java/org/apache/activemq/util/ListEditor.java
deleted file mode 100644
index 3cc5b14ee7..0000000000
--- a/activemq-core/src/main/java/org/apache/activemq/util/ListEditor.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- * 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.activemq.util;
-
-import java.beans.PropertyEditorSupport;
-import java.util.ArrayList;
-
-import org.apache.activemq.command.ActiveMQDestination;
-import org.springframework.util.StringUtils;
-
-/**
- * Used to serialize lists of ActiveMQDestinations.
- * @see org.apache.activemq.util.IntrospectionSupport
- */
-@Deprecated
-public class ListEditor extends PropertyEditorSupport {
-
- public static final String DEFAULT_SEPARATOR = ",";
-
- public String getAsText() {
- return getValue().toString();
- }
-
-
- public void setAsText(String text) throws IllegalArgumentException {
- text = text.substring(1, text.length() - 1);
- String[] array = StringUtils.delimitedListToStringArray(text, ListEditor.DEFAULT_SEPARATOR, null);
- ArrayList list = new ArrayList();
- for (String item : array) {
- list.add(ActiveMQDestination.createDestination(item.trim(), ActiveMQDestination.QUEUE_TYPE));
- }
- setValue(list);
- }
-
-}
diff --git a/activemq-core/src/main/java/org/apache/activemq/util/MemoryIntPropertyEditor.java b/activemq-core/src/main/java/org/apache/activemq/util/MemoryIntPropertyEditor.java
index 099e5b93a6..6c167a58fa 100644
--- a/activemq-core/src/main/java/org/apache/activemq/util/MemoryIntPropertyEditor.java
+++ b/activemq-core/src/main/java/org/apache/activemq/util/MemoryIntPropertyEditor.java
@@ -21,10 +21,14 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
+ * Used by xbean to set integers.
+ *
+ * Important: Do not use this for other purposes than xbean, as property editors
+ * are not thread safe, and they are slow to use.
+ *
* Converts string values like "20 Mb", "1024kb", and "1g" to int values in
* bytes.
*/
-@Deprecated
public class MemoryIntPropertyEditor extends PropertyEditorSupport {
public void setAsText(String text) throws IllegalArgumentException {
diff --git a/activemq-core/src/main/java/org/apache/activemq/util/MemoryPropertyEditor.java b/activemq-core/src/main/java/org/apache/activemq/util/MemoryPropertyEditor.java
index b906d3bd0b..09fe06e664 100644
--- a/activemq-core/src/main/java/org/apache/activemq/util/MemoryPropertyEditor.java
+++ b/activemq-core/src/main/java/org/apache/activemq/util/MemoryPropertyEditor.java
@@ -21,10 +21,14 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
+ * Used by xbean to set longs.
+ *
+ * Important: Do not use this for other purposes than xbean, as property editors
+ * are not thread safe, and they are slow to use.
+ *
* Converts string values like "20 Mb", "1024kb", and "1g" to long values in
* bytes.
*/
-@Deprecated
public class MemoryPropertyEditor extends PropertyEditorSupport {
public void setAsText(String text) throws IllegalArgumentException {
diff --git a/activemq-core/src/main/java/org/apache/activemq/util/StringToListOfActiveMQDestinationConverter.java b/activemq-core/src/main/java/org/apache/activemq/util/StringToListOfActiveMQDestinationConverter.java
new file mode 100644
index 0000000000..bd35513084
--- /dev/null
+++ b/activemq-core/src/main/java/org/apache/activemq/util/StringToListOfActiveMQDestinationConverter.java
@@ -0,0 +1,84 @@
+/**
+ * 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.activemq.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.activemq.command.ActiveMQDestination;
+import org.springframework.util.StringUtils;
+
+/**
+ * Special converter for String -> List to be used instead of a
+ * {@link java.beans.PropertyEditor} which otherwise causes
+ * memory leaks as the JDK {@link java.beans.PropertyEditorManager}
+ * is a static class and has strong references to classes, causing
+ * problems in hot-deployment environments.
+ */
+public class StringToListOfActiveMQDestinationConverter {
+
+ public static List convertToActiveMQDestination(Object value) {
+ if (value == null) {
+ return null;
+ }
+
+ // text must be enclosed with []
+
+ String text = value.toString();
+ if (text.startsWith("[") && text.endsWith("]")) {
+ text = text.substring(1, text.length() - 1);
+ String[] array = StringUtils.delimitedListToStringArray(text, ",", null);
+
+ List list = new ArrayList();
+ for (String item : array) {
+ list.add(ActiveMQDestination.createDestination(item.trim(), ActiveMQDestination.QUEUE_TYPE));
+ }
+ return list;
+ } else {
+ return null;
+ }
+ }
+
+ public static String convertFromActiveMQDestination(Object value) {
+ if (value == null) {
+ return null;
+ }
+
+ StringBuilder sb = new StringBuilder("[");
+ if (value instanceof List) {
+ List list = (List) value;
+ for (int i = 0; i < list.size(); i++) {
+ Object e = list.get(i);
+ if (e instanceof ActiveMQDestination) {
+ ActiveMQDestination destination = (ActiveMQDestination) e;
+ sb.append(destination);
+ if (i < list.size() - 1) {
+ sb.append(", ");
+ }
+ }
+ }
+ }
+ sb.append("]");
+
+ if (sb.length() > 2) {
+ return sb.toString();
+ } else {
+ return null;
+ }
+ }
+
+}
diff --git a/activemq-core/src/main/java/org/apache/activemq/util/TypeConversionSupport.java b/activemq-core/src/main/java/org/apache/activemq/util/TypeConversionSupport.java
index 1363f85ed0..2b6dfa011d 100755
--- a/activemq-core/src/main/java/org/apache/activemq/util/TypeConversionSupport.java
+++ b/activemq-core/src/main/java/org/apache/activemq/util/TypeConversionSupport.java
@@ -16,12 +16,17 @@
*/
package org.apache.activemq.util;
+import java.net.URI;
+import java.net.URISyntaxException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.apache.activemq.command.ActiveMQDestination;
+/**
+ * Type conversion support for ActiveMQ.
+ */
public final class TypeConversionSupport {
private static class ConversionKey {
@@ -45,7 +50,7 @@ public final class TypeConversionSupport {
}
}
- interface Converter {
+ public interface Converter {
Object convert(Object value);
}
@@ -138,16 +143,25 @@ public final class TypeConversionSupport {
return ActiveMQDestination.createDestination((String)value, ActiveMQDestination.QUEUE_TYPE);
}
});
+ CONVERSION_MAP.put(new ConversionKey(String.class, URI.class), new Converter() {
+ public Object convert(Object value) {
+ String text = value.toString();
+ try {
+ return new URI(text);
+ } catch (URISyntaxException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
}
private TypeConversionSupport() {
}
- public static Object convert(Object value, Class type) {
-
+ public static Object convert(Object value, Class to) {
if (value == null) {
// lets avoid NullPointerException when converting to boolean for null values
- if (boolean.class.isAssignableFrom(type)) {
+ if (boolean.class.isAssignableFrom(to)) {
return Boolean.FALSE;
}
return null;
@@ -155,12 +169,12 @@ public final class TypeConversionSupport {
// eager same instance type test to avoid the overhead of invoking the type converter
// if already same type
- if (type.isInstance(value)) {
- return type.cast(value);
+ if (to.isInstance(value)) {
+ return to.cast(value);
}
// lookup converter
- Converter c = CONVERSION_MAP.get(new ConversionKey(value.getClass(), type));
+ Converter c = lookupConverter(value.getClass(), to);
if (c != null) {
return c.convert(value);
} else {
@@ -168,4 +182,42 @@ public final class TypeConversionSupport {
}
}
+ public static Converter lookupConverter(Class from, Class to) {
+ // use wrapped type for primitives
+ if (from.isPrimitive()) {
+ from = convertPrimitiveTypeToWrapperType(from);
+ }
+ if (to.isPrimitive()) {
+ to = convertPrimitiveTypeToWrapperType(to);
+ }
+
+ return CONVERSION_MAP.get(new ConversionKey(from, to));
+ }
+
+ /**
+ * Converts primitive types such as int to its wrapper type like
+ * {@link Integer}
+ */
+ private static Class> convertPrimitiveTypeToWrapperType(Class> type) {
+ Class> rc = type;
+ if (type.isPrimitive()) {
+ if (type == int.class) {
+ rc = Integer.class;
+ } else if (type == long.class) {
+ rc = Long.class;
+ } else if (type == double.class) {
+ rc = Double.class;
+ } else if (type == float.class) {
+ rc = Float.class;
+ } else if (type == short.class) {
+ rc = Short.class;
+ } else if (type == byte.class) {
+ rc = Byte.class;
+ } else if (type == boolean.class) {
+ rc = Boolean.class;
+ }
+ }
+ return rc;
+ }
+
}
diff --git a/activemq-core/src/test/java/org/apache/activemq/util/ReflectionSupportTest.java b/activemq-core/src/test/java/org/apache/activemq/util/ReflectionSupportTest.java
index 0f0095b738..89759219f2 100755
--- a/activemq-core/src/test/java/org/apache/activemq/util/ReflectionSupportTest.java
+++ b/activemq-core/src/test/java/org/apache/activemq/util/ReflectionSupportTest.java
@@ -52,6 +52,7 @@ public class ReflectionSupportTest extends TestCase {
map.put("favorites", favoritesString);
map.put("nonFavorites", nonFavoritesString);
map.put("others", null);
+ map.put("systems", "windows,mac");
IntrospectionSupport.setProperties(pojo, map);
@@ -62,6 +63,8 @@ public class ReflectionSupportTest extends TestCase {
assertEquals(favorites, pojo.getFavorites());
assertEquals(nonFavorites, pojo.getNonFavorites());
assertNull(pojo.getOthers());
+ assertEquals("windows", pojo.getSystems()[0]);
+ assertEquals("mac", pojo.getSystems()[1]);
}
public void testGetProperties() {
@@ -72,6 +75,7 @@ public class ReflectionSupportTest extends TestCase {
pojo.setFavorites(favorites);
pojo.setNonFavorites(nonFavorites);
pojo.setOthers(null);
+ pojo.setSystems(new String[]{"windows", "mac"});
Properties props = new Properties();
@@ -79,10 +83,11 @@ public class ReflectionSupportTest extends TestCase {
assertEquals("Dejan", props.get("name"));
assertEquals("31", props.get("age"));
- assertEquals("True", props.get("enabled"));
+ assertEquals("true", props.get("enabled"));
assertEquals(favoritesString, props.get("favorites"));
assertEquals(nonFavoritesString, props.get("nonFavorites"));
assertNull(props.get("others"));
+ assertEquals("windows,mac", props.get("systems"));
}
public void testSetBoolean() {
diff --git a/activemq-core/src/test/java/org/apache/activemq/util/SimplePojo.java b/activemq-core/src/test/java/org/apache/activemq/util/SimplePojo.java
index ac19075463..841e2a9c56 100755
--- a/activemq-core/src/test/java/org/apache/activemq/util/SimplePojo.java
+++ b/activemq-core/src/test/java/org/apache/activemq/util/SimplePojo.java
@@ -31,6 +31,7 @@ public class SimplePojo {
List favorites = new ArrayList();
List nonFavorites = new ArrayList();
List others = new ArrayList();
+ String[] systems;
public int getAge() {
return age;
@@ -74,5 +75,10 @@ public class SimplePojo {
public void setOthers(List others) {
this.others = others;
}
-
+ public String[] getSystems() {
+ return systems;
+ }
+ public void setSystems(String[] systems) {
+ this.systems = systems;
+ }
}