XBEAN-310 introducing PropertyEditorRegistry as a replacement of PropertyEditors static utility
git-svn-id: https://svn.apache.org/repos/asf/geronimo/xbean/trunk@1837693 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/AbstractCollectionConverter.java b/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/AbstractCollectionConverter.java
index d5dcea7..27b3712 100644
--- a/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/AbstractCollectionConverter.java
+++ b/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/AbstractCollectionConverter.java
@@ -36,12 +36,14 @@
public AbstractCollectionConverter(Class type, PropertyEditor editor) {
super(type);
- if (editor == null) throw new NullPointerException("editor is null");
+ if (editor == null) {
+ throw new NullPointerException("editor is null");
+ }
this.editor = editor;
}
protected final Object toObjectImpl(String text) {
- List list = CollectionUtil.toList(text, editor);
+ List list = CollectionUtil.toList(text, getEditor());
if (list == null) {
return null;
}
@@ -62,7 +64,11 @@
values = (Collection) value;
}
- String text = CollectionUtil.toString(values, editor);
+ String text = CollectionUtil.toString(values, getEditor());
return text;
}
+
+ protected PropertyEditor getEditor() {
+ return editor;
+ }
}
diff --git a/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/ConstructorConverter.java b/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/ConstructorConverter.java
index 13fe849..2b09bc0 100644
--- a/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/ConstructorConverter.java
+++ b/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/ConstructorConverter.java
@@ -43,7 +43,6 @@
} catch (final NoSuchMethodException e) {
// fine
}
-
return null;
}
}
diff --git a/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/Converter.java b/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/Converter.java
index d80df32..e696413 100644
--- a/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/Converter.java
+++ b/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/Converter.java
@@ -24,7 +24,7 @@
public interface Converter extends PropertyEditor {
/**
* Gets the the type of object supported by this converter.
- * @return
+ * @return the type used for that converter.
*/
Class getType();
diff --git a/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/EnumConverter.java b/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/EnumConverter.java
index e4e39e5..b88c378 100644
--- a/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/EnumConverter.java
+++ b/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/EnumConverter.java
@@ -27,6 +27,12 @@
super(type);
}
+ @Override
+ protected String toStringImpl(final Object value) {
+ return Enum.class.cast(value).name();
+ }
+
+ @Override
protected Object toObjectImpl(String text) {
Class type = getType();
@@ -34,12 +40,13 @@
return Enum.valueOf(type, text);
} catch (Exception cause) {
try {
- int index = Integer.parseInt(text);
- Method method = type.getMethod("values");
- Object[] values = (Object[]) method.invoke(null);
+ final int index = Integer.parseInt(text);
+ final Method method = type.getMethod("values");
+ final Object[] values = (Object[]) method.invoke(null);
return values[index];
- } catch (NumberFormatException e) {
- } catch (Exception e) {
+ } catch (final NumberFormatException e) {
+ // no-op
+ } catch (final Exception e) {
cause = e;
}
diff --git a/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/Primitives.java b/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/Primitives.java
new file mode 100644
index 0000000..57530dd
--- /dev/null
+++ b/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/Primitives.java
@@ -0,0 +1,71 @@
+/**
+ * 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.xbean.propertyeditor;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+public final class Primitives {
+ private static final Map<Class, Class> PRIMITIVE_TO_WRAPPER;
+ private static final Map<Class, Class> WRAPPER_TO_PRIMITIVE;
+
+ static {
+ {
+ final Map<Class, Class> map = new HashMap<Class, Class>();
+ map.put(boolean.class, Boolean.class);
+ map.put(char.class, Character.class);
+ map.put(byte.class, Byte.class);
+ map.put(short.class, Short.class);
+ map.put(int.class, Integer.class);
+ map.put(long.class, Long.class);
+ map.put(float.class, Float.class);
+ map.put(double.class, Double.class);
+ PRIMITIVE_TO_WRAPPER = Collections.unmodifiableMap(map);
+ }
+
+ {
+ final Map<Class, Class> map = new HashMap<Class, Class>();
+ map.put(Boolean.class, boolean.class);
+ map.put(Character.class, char.class);
+ map.put(Byte.class, byte.class);
+ map.put(Short.class, short.class);
+ map.put(Integer.class, int.class);
+ map.put(Long.class, long.class);
+ map.put(Float.class, float.class);
+ map.put(Double.class, double.class);
+ WRAPPER_TO_PRIMITIVE = Collections.unmodifiableMap(map);
+ }
+ }
+
+ public static Class<?> findSibling(final Class<?> wrapperOrPrimitive) {
+ final Class aClass = PRIMITIVE_TO_WRAPPER.get(wrapperOrPrimitive);
+ return aClass != null ? aClass : WRAPPER_TO_PRIMITIVE.get(wrapperOrPrimitive);
+ }
+
+ public static Class<?> toWrapper(final Class<?> primitive) {
+ return PRIMITIVE_TO_WRAPPER.get(primitive);
+ }
+
+ public static Class<?> toPrimitive(final Class<?> wrapper) {
+ return WRAPPER_TO_PRIMITIVE.get(wrapper);
+ }
+
+ private Primitives() {
+ // no-op
+ }
+}
diff --git a/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/PropertyEditorConverter.java b/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/PropertyEditorConverter.java
new file mode 100644
index 0000000..0356404
--- /dev/null
+++ b/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/PropertyEditorConverter.java
@@ -0,0 +1,48 @@
+/**
+ * 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.xbean.propertyeditor;
+
+import java.beans.PropertyEditor;
+import java.beans.PropertyEditorManager;
+
+public class PropertyEditorConverter extends AbstractConverter {
+ public PropertyEditorConverter(final Class<?> type) {
+ super(type);
+ }
+
+ public String toStringImpl(final Object value) throws PropertyEditorException {
+ final PropertyEditor editor = PropertyEditorManager.findEditor(getType());
+ editor.setValue(value);
+ try {
+ return editor.getAsText();
+ } catch (final Exception e) {
+ throw new PropertyEditorException("Error while converting a \"" + getType().getSimpleName() + "\" to text " +
+ " using the property editor " + editor.getClass().getSimpleName(), e);
+ }
+ }
+
+ public Object toObjectImpl(final String text) throws PropertyEditorException {
+ final PropertyEditor editor = PropertyEditorManager.findEditor(getType());
+ editor.setAsText(text);
+ try {
+ return editor.getValue();
+ } catch (final Exception e) {
+ throw new PropertyEditorException("Error while converting \"" + text + "\" to a " + getType().getSimpleName() +
+ " using the property editor " + editor.getClass().getSimpleName(), e);
+ }
+ }
+}
diff --git a/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/PropertyEditorRegistry.java b/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/PropertyEditorRegistry.java
new file mode 100644
index 0000000..e7e17ed
--- /dev/null
+++ b/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/PropertyEditorRegistry.java
@@ -0,0 +1,447 @@
+/**
+ * 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.xbean.propertyeditor;
+
+import static java.util.Collections.unmodifiableMap;
+import static org.apache.xbean.recipe.RecipeHelper.getTypeParameters;
+import static org.apache.xbean.recipe.RecipeHelper.toClass;
+
+import java.beans.PropertyEditor;
+import java.beans.PropertyEditorManager;
+import java.io.Closeable;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.SortedSet;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.xbean.recipe.RecipeHelper;
+
+public class PropertyEditorRegistry implements Closeable {
+ private final ConcurrentMap<Type, Converter> registry = new ConcurrentHashMap<Type, Converter>();
+
+ public PropertyEditorRegistry registerDefaults() {
+ register(new ArrayListEditor());
+ register(new BigDecimalEditor());
+ register(new BigIntegerEditor());
+ register(new BooleanEditor());
+ register(new ByteEditor());
+ register(new CharacterEditor());
+ register(new ClassEditor());
+ register(new DateEditor());
+ register(new DoubleEditor());
+ register(new FileEditor());
+ register(new FloatEditor());
+ register(new HashMapEditor());
+ register(new HashtableEditor());
+ register(new IdentityHashMapEditor());
+ register(new Inet4AddressEditor());
+ register(new Inet6AddressEditor());
+ register(new InetAddressEditor());
+ register(new IntegerEditor());
+ register(new LinkedHashMapEditor());
+ register(new LinkedHashSetEditor());
+ register(new LinkedListEditor());
+ register(new ListEditor());
+ register(new LongEditor());
+ register(new MapEditor());
+ register(new ObjectNameEditor());
+ register(new PropertiesEditor());
+ register(new SetEditor());
+ register(new ShortEditor());
+ register(new SortedMapEditor());
+ register(new SortedSetEditor());
+ register(new StringEditor());
+ register(new TreeMapEditor());
+ register(new TreeSetEditor());
+ register(new URIEditor());
+ register(new URLEditor());
+ register(new LoggerConverter());
+ register(new PatternConverter());
+ register(new JndiConverter());
+ register(new VectorEditor());
+ register(new WeakHashMapEditor());
+
+ try {
+ register(new Log4jConverter());
+ } catch (final Throwable e) {
+ // no-op
+ }
+
+ try {
+ register(new CommonsLoggingConverter());
+ } catch (final Throwable e) {
+ // no-op
+ }
+
+ return this;
+ }
+
+ /**
+ * @return a read-only view of the converters.
+ */
+ public Map<Type, Converter> getRegistry() {
+ return unmodifiableMap(registry);
+ }
+
+ /**
+ * Register a converter in the registry.
+ *
+ * @param converter the converter to register.
+ * @return the previously existing converter for the corresponding type or null.
+ */
+ public Converter register(final Converter converter) {
+ if (converter == null) {
+ throw new NullPointerException("converter is null");
+ }
+ final Class<?> type = converter.getType();
+ final Converter existing = registry.put(type, converter);
+
+ final Class<?> sibling = Primitives.findSibling(type);
+ if (sibling != null) {
+ registry.put(sibling, converter);
+ }
+ return existing;
+ }
+
+ /**
+ * Unregister a converter.
+ *
+ * @param converter the converter to remove from the registry.
+ * @return the converter if found, or null.
+ */
+ public Converter unregister(final Converter converter) {
+ if (converter == null) {
+ throw new NullPointerException("converter is null");
+ }
+ return registry.remove(converter.getType());
+ }
+
+ public Converter findConverter(final Type type){
+ {
+ final Converter converter = findInternalConverter(type);
+ if (converter != null) {
+ if (!registry.containsKey(converter.getType())) {
+ register(converter);
+ }
+ return converter;
+ }
+ }
+
+ {
+ final Converter converter = createConverterFromEditor(type);
+ if (converter != null) {
+ register(converter);
+ return converter;
+ }
+ }
+
+ {
+ final Converter converter = findStructuralConverter(type);
+ if (converter != null) {
+ register(converter);
+ return converter;
+ }
+ }
+
+ return null;
+ }
+
+ public String toString(final Object value) throws PropertyEditorException {
+ if (value == null) {
+ throw new NullPointerException("value is null");
+ }
+ final Class type = unwrapClass(value);
+ final Converter converter = findConverter(type);
+ if (converter == null) {
+ throw new PropertyEditorException("Unable to find PropertyEditor for " + type.getSimpleName());
+ }
+ return converter.toString(value);
+ }
+
+ public Object getValue(final String type, final String value, final ClassLoader classLoader) throws PropertyEditorException {
+ if (type == null) {
+ throw new NullPointerException("type is null");
+ }
+ if (value == null) {
+ throw new NullPointerException("value is null");
+ }
+ if (classLoader == null) {
+ throw new NullPointerException("classLoader is null");
+ }
+
+ try {
+ return getValue(Class.forName(type, true, classLoader), value);
+ } catch (final ClassNotFoundException e) {
+ throw new PropertyEditorException("Type class could not be found: " + type);
+ }
+ }
+
+ public Object getValue(final Type type, final String value) throws PropertyEditorException {
+ if (type == null) {
+ throw new NullPointerException("type is null");
+ }
+ if (value == null) {
+ throw new NullPointerException("value is null");
+ }
+
+ final Converter converter = findConverter(type);
+ if (converter != null) {
+ return converter.toObject(value);
+ }
+
+ final Class clazz = toClass(type);
+
+ final Converter structuralConverter = findStructuralConverter(clazz);
+ if (structuralConverter != null) {
+ register(structuralConverter);
+ return structuralConverter.toObject(value);
+ }
+
+ throw new PropertyEditorException("Unable to find PropertyEditor for " + clazz.getSimpleName());
+ }
+
+ protected Class<?> unwrapClass(final Object value) {
+ Class<?> aClass = value.getClass();
+ while (aClass.getName().contains("$$")) {
+ aClass = aClass.getSuperclass();
+ if (aClass == null || aClass == Object.class) {
+ return value.getClass();
+ }
+ }
+ return aClass;
+ }
+
+ protected Converter findStructuralConverter(final Type type) {
+ if (type == null) throw new NullPointerException("type is null");
+
+ final Class clazz = toClass(type);
+
+ if (Enum.class.isAssignableFrom(clazz)){
+ return new EnumConverter(clazz);
+ }
+
+ {
+ final ConstructorConverter editor = ConstructorConverter.editor(clazz);
+ if (editor != null) {
+ return editor;
+ }
+ }
+
+ {
+ final StaticFactoryConverter editor = StaticFactoryConverter.editor(clazz);
+ if (editor != null) {
+ return editor;
+ }
+ }
+
+ return null;
+ }
+
+ protected Converter createConverterFromEditor(final Type type) {
+ if (type == null) {
+ throw new NullPointerException("type is null");
+ }
+
+ final Class<?> clazz = toClass(type);
+
+ // try to locate this directly from the editor manager first.
+ final PropertyEditor editor = PropertyEditorManager.findEditor(clazz);
+
+ // we're outta here if we got one.
+ if (editor != null) {
+ return new PropertyEditorConverter(clazz);
+ }
+
+
+ // it's possible this was a request for an array class. We might not
+ // recognize the array type directly, but the component type might be
+ // resolvable
+ if (clazz.isArray() && !clazz.getComponentType().isArray()) {
+ // do a recursive lookup on the base type
+ final PropertyEditor arrayEditor = findEditor(clazz.getComponentType());
+ // if we found a suitable editor for the base component type,
+ // wrapper this in an array adaptor for real use
+ if (findEditor(clazz.getComponentType()) != null) {
+ return new ArrayConverter(clazz, arrayEditor);
+ }
+ }
+
+ return null;
+ }
+
+ protected Converter findInternalConverter(final Type type) {
+ if (type == null) {
+ throw new NullPointerException("type is null");
+ }
+
+ final Class clazz = toClass(type);
+
+ // it's possible this was a request for an array class. We might not
+ // recognize the array type directly, but the component type might be
+ // resolvable
+ if (clazz.isArray() && !clazz.getComponentType().isArray()) {
+ // do a recursive lookup on the base type
+ PropertyEditor editor = findConverter(clazz.getComponentType());
+ // if we found a suitable editor for the base component type,
+ // wrapper this in an array adaptor for real use
+ if (editor != null) {
+ return new ArrayConverter(clazz, editor);
+ }
+ return null;
+ }
+
+ if (Collection.class.isAssignableFrom(clazz)){
+ Type[] types = getTypeParameters(Collection.class, type);
+
+ Type componentType = String.class;
+ if (types != null && types.length == 1 && types[0] instanceof Class) {
+ componentType = types[0];
+ }
+
+ PropertyEditor editor = findConverter(componentType);
+
+ if (editor != null){
+ if (RecipeHelper.hasDefaultConstructor(clazz)) {
+ return new GenericCollectionConverter(clazz, editor);
+ } else if (SortedSet.class.isAssignableFrom(clazz)) {
+ return new GenericCollectionConverter(TreeSet.class, editor);
+ } else if (Set.class.isAssignableFrom(clazz)) {
+ return new GenericCollectionConverter(LinkedHashSet.class, editor);
+ }
+ return new GenericCollectionConverter(ArrayList.class, editor);
+ }
+
+ return null;
+ }
+
+ if (Map.class.isAssignableFrom(clazz)){
+ Type[] types = getTypeParameters(Map.class, type);
+
+ Type keyType = String.class;
+ Type valueType = String.class;
+ if (types != null && types.length == 2 && types[0] instanceof Class && types[1] instanceof Class) {
+ keyType = types[0];
+ valueType = types[1];
+ }
+
+ final Converter keyConverter = findConverter(keyType);
+ final Converter valueConverter = findConverter(valueType);
+
+ if (keyConverter != null && valueConverter != null){
+ if (RecipeHelper.hasDefaultConstructor(clazz)) {
+ return new GenericMapConverter(clazz, keyConverter, valueConverter);
+ } else if (SortedMap.class.isAssignableFrom(clazz)) {
+ return new GenericMapConverter(TreeMap.class, keyConverter, valueConverter);
+ } else if (ConcurrentMap.class.isAssignableFrom(clazz)) {
+ return new GenericMapConverter(ConcurrentHashMap.class, keyConverter, valueConverter);
+ }
+ return new GenericMapConverter(LinkedHashMap.class, keyConverter, valueConverter);
+ }
+
+ return null;
+ }
+
+ Converter converter = registry.get(clazz);
+
+ // we're outta here if we got one.
+ if (converter != null) {
+ return converter;
+ }
+
+ final Class[] declaredClasses = clazz.getDeclaredClasses();
+ for (final Class<?> declaredClass : declaredClasses) {
+ if (Converter.class.isAssignableFrom(declaredClass)) {
+ try {
+ converter = (Converter) declaredClass.newInstance();
+ register(converter);
+
+ // try to get the converter from the registry... the converter
+ // created above may have been for another class
+ converter = registry.get(clazz);
+ if (converter != null) {
+ return converter;
+ }
+ } catch (Exception e) {
+ // no-op
+ }
+
+ }
+ }
+
+ // nothing found
+ return null;
+ }
+
+ /**
+ * Locate a property editor for qiven class of object.
+ *
+ * @param type The target object class of the property.
+ * @return The resolved editor, if any. Returns null if a suitable editor
+ * could not be located.
+ */
+ protected PropertyEditor findEditor(final Type type) {
+ if (type == null) throw new NullPointerException("type is null");
+
+ Class clazz = toClass(type);
+
+ // try to locate this directly from the editor manager first.
+ PropertyEditor editor = PropertyEditorManager.findEditor(clazz);
+
+ // we're outta here if we got one.
+ if (editor != null) {
+ return editor;
+ }
+
+
+ // it's possible this was a request for an array class. We might not
+ // recognize the array type directly, but the component type might be
+ // resolvable
+ if (clazz.isArray() && !clazz.getComponentType().isArray()) {
+ // do a recursive lookup on the base type
+ editor = findEditor(clazz.getComponentType());
+ // if we found a suitable editor for the base component type,
+ // wrapper this in an array adaptor for real use
+ if (editor != null) {
+ return new ArrayConverter(clazz, editor);
+ }
+ }
+
+ // nothing found
+ return null;
+ }
+
+ /**
+ * Release closeable converters.
+ */
+ public void close() {
+ for (final Converter converter : registry.values()) {
+ if (Closeable.class.isInstance(converter)) {
+ Closeable.class.cast(converter);
+ }
+ }
+ registry.clear();
+ }
+}
diff --git a/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/PropertyEditors.java b/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/PropertyEditors.java
index bd27b11..dda3bf4 100644
--- a/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/PropertyEditors.java
+++ b/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/PropertyEditors.java
@@ -16,29 +16,11 @@
*/
package org.apache.xbean.propertyeditor;
-import static org.apache.xbean.recipe.RecipeHelper.getTypeParameters;
-import static org.apache.xbean.recipe.RecipeHelper.*;
-import org.apache.xbean.recipe.RecipeHelper;
-
-import java.beans.PropertyEditor;
import java.beans.PropertyEditorManager;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Collection;
-import java.util.SortedSet;
-import java.util.Set;
-import java.util.TreeSet;
-import java.util.LinkedHashSet;
-import java.util.ArrayList;
-import java.util.SortedMap;
-import java.util.TreeMap;
-import java.util.LinkedHashMap;
-import java.util.Map.Entry;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.ConcurrentHashMap;
import java.lang.reflect.Type;
+import com.sun.org.apache.regexp.internal.RE;
+
/**
* The property editor manager. This orchestrates Geronimo usage of
* property editors, allowing additional search paths to be added and
@@ -46,91 +28,27 @@
*
* @version $Rev: 6687 $
*/
+@Deprecated // this is all static and leaks, use PropertyEditorRegistry
public class PropertyEditors {
- private static final Map<Class, Converter> registry = Collections.synchronizedMap(new ReferenceIdentityMap());
- private static final Map<Class, Class> PRIMITIVE_TO_WRAPPER;
- private static final Map<Class, Class> WRAPPER_TO_PRIMITIVE;
private static boolean registerWithVM;
-
- /**
- * Register all of the built in converters
- */
- static {
- Map<Class, Class> map = new HashMap<Class, Class>();
- map.put(boolean.class, Boolean.class);
- map.put(char.class, Character.class);
- map.put(byte.class, Byte.class);
- map.put(short.class, Short.class);
- map.put(int.class, Integer.class);
- map.put(long.class, Long.class);
- map.put(float.class, Float.class);
- map.put(double.class, Double.class);
- PRIMITIVE_TO_WRAPPER = Collections.unmodifiableMap(map);
-
-
- map = new HashMap<Class, Class>();
- map.put(Boolean.class, boolean.class);
- map.put(Character.class, char.class);
- map.put(Byte.class, byte.class);
- map.put(Short.class, short.class);
- map.put(Integer.class, int.class);
- map.put(Long.class, long.class);
- map.put(Float.class, float.class);
- map.put(Double.class, double.class);
- WRAPPER_TO_PRIMITIVE = Collections.unmodifiableMap(map);
-
- // Explicitly register the types
- registerConverter(new ArrayListEditor());
- registerConverter(new BigDecimalEditor());
- registerConverter(new BigIntegerEditor());
- registerConverter(new BooleanEditor());
- registerConverter(new ByteEditor());
- registerConverter(new CharacterEditor());
- registerConverter(new ClassEditor());
- registerConverter(new DateEditor());
- registerConverter(new DoubleEditor());
- registerConverter(new FileEditor());
- registerConverter(new FloatEditor());
- registerConverter(new HashMapEditor());
- registerConverter(new HashtableEditor());
- registerConverter(new IdentityHashMapEditor());
- registerConverter(new Inet4AddressEditor());
- registerConverter(new Inet6AddressEditor());
- registerConverter(new InetAddressEditor());
- registerConverter(new IntegerEditor());
- registerConverter(new LinkedHashMapEditor());
- registerConverter(new LinkedHashSetEditor());
- registerConverter(new LinkedListEditor());
- registerConverter(new ListEditor());
- registerConverter(new LongEditor());
- registerConverter(new MapEditor());
- registerConverter(new ObjectNameEditor());
- registerConverter(new PropertiesEditor());
- registerConverter(new SetEditor());
- registerConverter(new ShortEditor());
- registerConverter(new SortedMapEditor());
- registerConverter(new SortedSetEditor());
- registerConverter(new StringEditor());
- registerConverter(new TreeMapEditor());
- registerConverter(new TreeSetEditor());
- registerConverter(new URIEditor());
- registerConverter(new URLEditor());
- registerConverter(new LoggerConverter());
- registerConverter(new PatternConverter());
- registerConverter(new JndiConverter());
- registerConverter(new VectorEditor());
- registerConverter(new WeakHashMapEditor());
-
- try {
- registerConverter(new Log4jConverter());
- } catch (Throwable e) {
+ private static final PropertyEditorRegistry REGISTRY = new PropertyEditorRegistry() {
+ {
+ registerDefaults();
}
- try {
- registerConverter(new CommonsLoggingConverter());
- } catch (Throwable e) {
+ @Override
+ public Converter register(final Converter converter) {
+ final Converter register = super.register(converter);
+ if (registerWithVM) {
+ PropertyEditorManager.registerEditor(converter.getType(), converter.getClass());
+ final Class<?> sibling = Primitives.findSibling(converter.getType());
+ if (sibling != null) {
+ PropertyEditorManager.registerEditor(sibling, converter.getClass());
+ }
+ }
+ return register;
}
- }
+ };
/**
* Are converters registered with the VM PropertyEditorManager. By default
@@ -150,322 +68,51 @@
public static void setRegisterWithVM(boolean registerWithVM) {
if (PropertyEditors.registerWithVM != registerWithVM) {
PropertyEditors.registerWithVM = registerWithVM;
-
- // register all converters with the VM
if (registerWithVM) {
- for (Entry<Class, Converter> entry : registry.entrySet()) {
- Class type = entry.getKey();
- Converter converter = entry.getValue();
- PropertyEditorManager.registerEditor(type, converter.getClass());
+ for (final Converter converter : REGISTRY.getRegistry().values()) {
+ PropertyEditorManager.registerEditor(converter.getType(), converter.getClass());
}
}
}
}
public static void registerConverter(Converter converter) {
- if (converter == null) throw new NullPointerException("editor is null");
- Class type = converter.getType();
- registry.put(type, converter);
- if (registerWithVM) {
- PropertyEditorManager.registerEditor(type, converter.getClass());
- }
-
- if (PRIMITIVE_TO_WRAPPER.containsKey(type)) {
- Class wrapperType = PRIMITIVE_TO_WRAPPER.get(type);
- registry.put(wrapperType, converter);
- if (registerWithVM) {
- PropertyEditorManager.registerEditor(wrapperType, converter.getClass());
- }
- } else if (WRAPPER_TO_PRIMITIVE.containsKey(type)) {
- Class primitiveType = WRAPPER_TO_PRIMITIVE.get(type);
- registry.put(primitiveType, converter);
- if (registerWithVM) {
- PropertyEditorManager.registerEditor(primitiveType, converter.getClass());
- }
- }
+ REGISTRY.register(converter);
}
- public static boolean canConvert(String type, ClassLoader classLoader) {
- if (type == null) throw new NullPointerException("type is null");
- if (classLoader == null) throw new NullPointerException("classLoader is null");
+ public static boolean canConvert(final String type, final ClassLoader classLoader) {
+ if (type == null) {
+ throw new NullPointerException("type is null");
+ }
+ if (classLoader == null) {
+ throw new NullPointerException("classLoader is null");
+ }
- // load using the ClassLoading utility, which also manages arrays and primitive classes.
- Class typeClass;
try {
- typeClass = Class.forName(type, true, classLoader);
+ return REGISTRY.findConverter(Class.forName(type, true, classLoader)) != null;
} catch (ClassNotFoundException e) {
throw new PropertyEditorException("Type class could not be found: " + type);
}
+ }
- return canConvert(typeClass);
+ public static boolean canConvert(final Class<?> type) {
+ return REGISTRY.findConverter(type) != null;
+ }
+
+ public static String toString(final Object value) throws PropertyEditorException {
+ return REGISTRY.toString(value);
+ }
+
+ public static Object getValue(final String type, final String value, final ClassLoader classLoader) throws PropertyEditorException {
+ return REGISTRY.getValue(type, value, classLoader);
}
- public static boolean canConvert(Class type) {
- PropertyEditor editor = findConverterOrEditor(type);
-
- return editor != null;
+ public static Object getValue(final Type type, final String value) throws PropertyEditorException {
+ return REGISTRY.getValue(type, value);
}
- private static PropertyEditor findConverterOrEditor(Type type){
- Converter converter = findConverter(type);
- if (converter != null) {
- return converter;
- }
-
- // fall back to a property editor
- PropertyEditor editor = findEditor(type);
- if (editor != null) {
- return editor;
- }
-
- converter = findBuiltinConverter(type);
- if (converter != null) {
- return converter;
- }
-
- return null;
- }
-
- public static String toString(Object value) throws PropertyEditorException {
- if (value == null) throw new NullPointerException("value is null");
-
- // get an editor for this type
- Class type = value.getClass();
-
- PropertyEditor editor = findConverterOrEditor(type);
-
- if (editor instanceof Converter) {
- Converter converter = (Converter) editor;
- return converter.toString(value);
- }
-
- if (editor == null) {
- throw new PropertyEditorException("Unable to find PropertyEditor for " + type.getSimpleName());
- }
-
- // create the string value
- editor.setValue(value);
- String textValue;
- try {
- textValue = editor.getAsText();
- } catch (Exception e) {
- throw new PropertyEditorException("Error while converting a \"" + type.getSimpleName() + "\" to text " +
- " using the property editor " + editor.getClass().getSimpleName(), e);
- }
- return textValue;
- }
-
- public static Object getValue(String type, String value, ClassLoader classLoader) throws PropertyEditorException {
- if (type == null) throw new NullPointerException("type is null");
- if (value == null) throw new NullPointerException("value is null");
- if (classLoader == null) throw new NullPointerException("classLoader is null");
-
- // load using the ClassLoading utility, which also manages arrays and primitive classes.
- Class typeClass;
- try {
- typeClass = Class.forName(type, true, classLoader);
- } catch (ClassNotFoundException e) {
- throw new PropertyEditorException("Type class could not be found: " + type);
- }
-
- return getValue(typeClass, value);
-
- }
-
- public static Object getValue(Type type, String value) throws PropertyEditorException {
- if (type == null) throw new NullPointerException("type is null");
- if (value == null) throw new NullPointerException("value is null");
-
- PropertyEditor editor = findConverterOrEditor(type);
-
- if (editor instanceof Converter) {
- Converter converter = (Converter) editor;
- return converter.toObject(value);
- }
-
- Class clazz = toClass(type);
-
- if (editor == null) editor = ConstructorConverter.editor(toClass(type));
- if (editor == null) editor = StaticFactoryConverter.editor(toClass(type));
-
- if (editor == null) {
- throw new PropertyEditorException("Unable to find PropertyEditor for " + clazz.getSimpleName());
- }
-
- editor.setAsText(value);
- Object objectValue;
- try {
- objectValue = editor.getValue();
- } catch (Exception e) {
- throw new PropertyEditorException("Error while converting \"" + value + "\" to a " + clazz.getSimpleName() +
- " using the property editor " + editor.getClass().getSimpleName(), e);
- }
- return objectValue;
- }
-
- private static Converter findBuiltinConverter(Type type) {
- if (type == null) throw new NullPointerException("type is null");
-
- final Class clazz = toClass(type);
-
- if (Enum.class.isAssignableFrom(clazz)){
- return new EnumConverter(clazz);
- }
-
- {
- final ConstructorConverter editor = ConstructorConverter.editor(clazz);
- if (editor != null) return editor;
- }
-
- {
- final StaticFactoryConverter editor = StaticFactoryConverter.editor(clazz);
- if (editor != null) return editor;
- }
-
- return null;
- }
-
- private static Converter findConverter(Type type) {
- if (type == null) throw new NullPointerException("type is null");
-
- Class clazz = toClass(type);
-
-
-
- // it's possible this was a request for an array class. We might not
- // recognize the array type directly, but the component type might be
- // resolvable
- if (clazz.isArray() && !clazz.getComponentType().isArray()) {
- // do a recursive lookup on the base type
- PropertyEditor editor = findConverterOrEditor(clazz.getComponentType());
- // if we found a suitable editor for the base component type,
- // wrapper this in an array adaptor for real use
- if (editor != null) {
- return new ArrayConverter(clazz, editor);
- } else {
- return null;
- }
- }
-
- if (Collection.class.isAssignableFrom(clazz)){
- Type[] types = getTypeParameters(Collection.class, type);
-
- Type componentType = String.class;
- if (types != null && types.length == 1 && types[0] instanceof Class) {
- componentType = types[0];
- }
-
- PropertyEditor editor = findConverterOrEditor(componentType);
-
- if (editor != null){
- if (RecipeHelper.hasDefaultConstructor(clazz)) {
- return new GenericCollectionConverter(clazz, editor);
- } else if (SortedSet.class.isAssignableFrom(clazz)) {
- return new GenericCollectionConverter(TreeSet.class, editor);
- } else if (Set.class.isAssignableFrom(clazz)) {
- return new GenericCollectionConverter(LinkedHashSet.class, editor);
- } else {
- return new GenericCollectionConverter(ArrayList.class, editor);
- }
- }
-
- return null;
- }
-
- if (Map.class.isAssignableFrom(clazz)){
- Type[] types = getTypeParameters(Map.class, type);
-
- Type keyType = String.class;
- Type valueType = String.class;
- if (types != null && types.length == 2 && types[0] instanceof Class && types[1] instanceof Class) {
- keyType = types[0];
- valueType = types[1];
- }
-
- PropertyEditor keyConverter = findConverterOrEditor(keyType);
- PropertyEditor valueConverter = findConverterOrEditor(valueType);
-
- if (keyConverter != null && valueConverter != null){
- if (RecipeHelper.hasDefaultConstructor(clazz)) {
- return new GenericMapConverter(clazz, keyConverter, valueConverter);
- } else if (SortedMap.class.isAssignableFrom(clazz)) {
- return new GenericMapConverter(TreeMap.class, keyConverter, valueConverter);
- } else if (ConcurrentMap.class.isAssignableFrom(clazz)) {
- return new GenericMapConverter(ConcurrentHashMap.class, keyConverter, valueConverter);
- } else {
- return new GenericMapConverter(LinkedHashMap.class, keyConverter, valueConverter);
- }
- }
-
- return null;
- }
-
- Converter converter = registry.get(clazz);
-
- // we're outta here if we got one.
- if (converter != null) {
- return converter;
- }
-
- Class[] declaredClasses = clazz.getDeclaredClasses();
- for (Class declaredClass : declaredClasses) {
- if (Converter.class.isAssignableFrom(declaredClass)) {
- try {
- converter = (Converter) declaredClass.newInstance();
- registerConverter(converter);
-
- // try to get the converter from the registry... the converter
- // created above may have been for another class
- converter = registry.get(clazz);
- if (converter != null) {
- return converter;
- }
- } catch (Exception e) {
- }
-
- }
- }
-
- // nothing found
- return null;
- }
-
- /**
- * Locate a property editor for qiven class of object.
- *
- * @param type The target object class of the property.
- * @return The resolved editor, if any. Returns null if a suitable editor
- * could not be located.
- */
- private static PropertyEditor findEditor(Type type) {
- if (type == null) throw new NullPointerException("type is null");
-
- Class clazz = toClass(type);
-
- // try to locate this directly from the editor manager first.
- PropertyEditor editor = PropertyEditorManager.findEditor(clazz);
-
- // we're outta here if we got one.
- if (editor != null) {
- return editor;
- }
-
-
- // it's possible this was a request for an array class. We might not
- // recognize the array type directly, but the component type might be
- // resolvable
- if (clazz.isArray() && !clazz.getComponentType().isArray()) {
- // do a recursive lookup on the base type
- editor = findEditor(clazz.getComponentType());
- // if we found a suitable editor for the base component type,
- // wrapper this in an array adaptor for real use
- if (editor != null) {
- return new ArrayConverter(clazz, editor);
- }
- }
-
- // nothing found
- return null;
+ public static PropertyEditorRegistry registry() {
+ return REGISTRY;
}
}
diff --git a/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/PrototypeArrayConverter.java b/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/PrototypeArrayConverter.java
new file mode 100644
index 0000000..b84988d
--- /dev/null
+++ b/xbean-reflect/src/main/java/org/apache/xbean/propertyeditor/PrototypeArrayConverter.java
@@ -0,0 +1,57 @@
+/**
+ * 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.xbean.propertyeditor;
+
+import java.beans.PropertyEditor;
+import java.beans.PropertyEditorManager;
+import java.lang.reflect.Array;
+import java.util.List;
+import java.util.ListIterator;
+
+/**
+ * Adapter for editing array types.
+ *
+ * @version $Rev: 6687 $ $Date: 2005-12-28T21:08:56.733437Z $
+ */
+public final class PrototypeArrayConverter extends AbstractCollectionConverter {
+ private static final PropertyEditor MOCK_EDITOR = new StringEditor();
+
+ public PrototypeArrayConverter(Class type) {
+ super(type, MOCK_EDITOR);
+ if (!type.isArray()) {
+ throw new IllegalArgumentException("type is not an array " + type.getSimpleName());
+ }
+ if (type.getComponentType().isArray()) {
+ throw new IllegalArgumentException("type is a multi-dimensional array " + type.getSimpleName());
+ }
+ }
+
+ @Override
+ protected PropertyEditor getEditor() {
+ return PropertyEditorManager.findEditor(getType());
+ }
+
+ protected Object createCollection(final List list) {
+ final Object array = Array.newInstance(getType().getComponentType(), list.size());
+ for (final ListIterator iterator = list.listIterator(); iterator.hasNext();) {
+ final Object item = iterator.next();
+ int index = iterator.previousIndex();
+ Array.set(array, index, item);
+ }
+ return array;
+ }
+}
diff --git a/xbean-reflect/src/main/java/org/apache/xbean/recipe/ArrayRecipe.java b/xbean-reflect/src/main/java/org/apache/xbean/recipe/ArrayRecipe.java
index 8fb216a..f824f38 100644
--- a/xbean-reflect/src/main/java/org/apache/xbean/recipe/ArrayRecipe.java
+++ b/xbean-reflect/src/main/java/org/apache/xbean/recipe/ArrayRecipe.java
@@ -24,6 +24,8 @@
import java.util.EnumSet;
import java.util.List;
+import org.apache.xbean.propertyeditor.PropertyEditorRegistry;
+
/**
* @version $Rev$ $Date$
*/
@@ -31,6 +33,7 @@
private final List<Object> list;
private String typeName;
private Class typeClass;
+ private PropertyEditorRegistry registry;
private final EnumSet<Option> options = EnumSet.noneOf(Option.class);
public ArrayRecipe() {
@@ -56,6 +59,10 @@
list = new ArrayList<Object>(collectionRecipe.list);
}
+ public void setRegistry(final PropertyEditorRegistry registry) {
+ this.registry = registry;
+ }
+
public void allow(Option option) {
options.add(option);
}
@@ -108,7 +115,7 @@
int index = 0;
for (Object value : list) {
- value = RecipeHelper.convert(type, value, refAllowed);
+ value = RecipeHelper.convert(type, value, refAllowed, registry);
if (value instanceof Reference) {
Reference reference = (Reference) value;
diff --git a/xbean-reflect/src/main/java/org/apache/xbean/recipe/CollectionRecipe.java b/xbean-reflect/src/main/java/org/apache/xbean/recipe/CollectionRecipe.java
index 5ce24ec..d9f124d 100644
--- a/xbean-reflect/src/main/java/org/apache/xbean/recipe/CollectionRecipe.java
+++ b/xbean-reflect/src/main/java/org/apache/xbean/recipe/CollectionRecipe.java
@@ -29,6 +29,8 @@
import java.util.SortedSet;
import java.util.TreeSet;
+import org.apache.xbean.propertyeditor.PropertyEditorRegistry;
+
/**
* @version $Rev: 6685 $ $Date: 2005-12-28T00:29:37.967210Z $
*/
@@ -36,6 +38,7 @@
private final List<Object> list;
private String typeName;
private Class typeClass;
+ private PropertyEditorRegistry registry;
private final EnumSet<Option> options = EnumSet.noneOf(Option.class);
public CollectionRecipe() {
@@ -79,6 +82,10 @@
list = new ArrayList<Object>(collectionRecipe.list);
}
+ public void setRegistry(final PropertyEditorRegistry registry) {
+ this.registry = registry;
+ }
+
public void allow(Option option) {
options.add(option);
}
@@ -145,7 +152,7 @@
int index = 0;
for (Object value : list) {
- value = RecipeHelper.convert(componentType, value, refAllowed);
+ value = RecipeHelper.convert(componentType, value, refAllowed, registry);
if (value instanceof Reference) {
Reference reference = (Reference) value;
diff --git a/xbean-reflect/src/main/java/org/apache/xbean/recipe/MapRecipe.java b/xbean-reflect/src/main/java/org/apache/xbean/recipe/MapRecipe.java
index 9c88c46..874ecc3 100644
--- a/xbean-reflect/src/main/java/org/apache/xbean/recipe/MapRecipe.java
+++ b/xbean-reflect/src/main/java/org/apache/xbean/recipe/MapRecipe.java
@@ -32,6 +32,8 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+import org.apache.xbean.propertyeditor.PropertyEditorRegistry;
+
/**
* @version $Rev: 6687 $ $Date: 2005-12-28T21:08:56.733437Z $
*/
@@ -39,6 +41,7 @@
private final List<Object[]> entries;
private String typeName;
private Class typeClass;
+ private PropertyEditorRegistry registry;
private final EnumSet<Option> options = EnumSet.noneOf(Option.class);
public MapRecipe() {
@@ -81,6 +84,10 @@
entries = new ArrayList<Object[]>(mapRecipe.entries);
}
+ public void setRegistry(final PropertyEditorRegistry registry) {
+ this.registry = registry;
+ }
+
public void allow(Option option){
options.add(option);
}
@@ -163,8 +170,8 @@
// add map entries
boolean refAllowed = options.contains(Option.LAZY_ASSIGNMENT);
for (Object[] entry : entries) {
- Object key = RecipeHelper.convert(keyType, entry[0], refAllowed);
- Object value = RecipeHelper.convert(valueType, entry[1], refAllowed);
+ Object key = RecipeHelper.convert(keyType, entry[0], refAllowed, registry);
+ Object value = RecipeHelper.convert(valueType, entry[1], refAllowed, registry);
if (key instanceof Reference) {
// when the key reference and optional value reference are both resolved
diff --git a/xbean-reflect/src/main/java/org/apache/xbean/recipe/ObjectRecipe.java b/xbean-reflect/src/main/java/org/apache/xbean/recipe/ObjectRecipe.java
index aed13db..499bd19 100644
--- a/xbean-reflect/src/main/java/org/apache/xbean/recipe/ObjectRecipe.java
+++ b/xbean-reflect/src/main/java/org/apache/xbean/recipe/ObjectRecipe.java
@@ -29,6 +29,8 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+
+import org.apache.xbean.propertyeditor.PropertyEditorRegistry;
import org.apache.xbean.recipe.ReflectionUtil.*;
/**
@@ -40,6 +42,7 @@
private String factoryMethod;
private List<String> constructorArgNames;
private List<Class<?>> constructorArgTypes;
+ private PropertyEditorRegistry registry;
private final LinkedHashMap<Property,Object> properties = new LinkedHashMap<Property,Object>();
private final EnumSet<Option> options = EnumSet.of(Option.FIELD_INJECTION);
private final Map<String,Object> unsetProperties = new LinkedHashMap<String,Object>();
@@ -362,6 +365,10 @@
return null;
}
+ public void setRegistry(final PropertyEditorRegistry registry) {
+ this.registry = registry;
+ }
+
private void setProperties(Map<Property, Object> propertyValues, Object instance, Class clazz) {
// set remaining properties
for (Map.Entry<Property, Object> entry : RecipeHelper.prioritizeProperties(propertyValues)) {
@@ -378,20 +385,20 @@
List<Member> members = new ArrayList<Member>();
try {
if (propertyName instanceof SetterProperty){
- List<Method> setters = ReflectionUtil.findAllSetters(clazz, propertyName.name, propertyValue, options);
+ List<Method> setters = ReflectionUtil.findAllSetters(clazz, propertyName.name, propertyValue, options, registry);
for (Method setter : setters) {
MethodMember member = new MethodMember(setter);
members.add(member);
}
} else if (propertyName instanceof FieldProperty){
- FieldMember member = new FieldMember(ReflectionUtil.findField(clazz, propertyName.name, propertyValue, options));
+ FieldMember member = new FieldMember(ReflectionUtil.findField(clazz, propertyName.name, propertyValue, options, registry));
members.add(member);
} else if (propertyName instanceof AutoMatchProperty){
MissingAccessorException noField = null;
if (options.contains(Option.FIELD_INJECTION)) {
List<Field> fieldsByType = null;
try {
- fieldsByType = ReflectionUtil.findAllFieldsByType(clazz, propertyValue, options);
+ fieldsByType = ReflectionUtil.findAllFieldsByType(clazz, propertyValue, options, registry);
FieldMember member = new FieldMember(fieldsByType.iterator().next());
members.add(member);
} catch (MissingAccessorException e) {
@@ -412,7 +419,7 @@
if (members.isEmpty()) {
List<Method> settersByType;
try {
- settersByType = ReflectionUtil.findAllSettersByType(clazz, propertyValue, options);
+ settersByType = ReflectionUtil.findAllSettersByType(clazz, propertyValue, options, registry);
MethodMember member = new MethodMember(settersByType.iterator().next());
members.add(member);
} catch (MissingAccessorException noSetter) {
@@ -450,7 +457,7 @@
throw new ConstructionException("No getter for " + names[i] + " property");
}
}
- List<Method> setters = ReflectionUtil.findAllSetters(clazz, names[names.length - 1], propertyValue, options);
+ List<Method> setters = ReflectionUtil.findAllSetters(clazz, names[names.length - 1], propertyValue, options, registry);
for (Method setter : setters) {
MethodMember member = new MethodMember(setter);
members.add(member);
@@ -459,7 +466,7 @@
// add setter members
MissingAccessorException noSetter = null;
try {
- List<Method> setters = ReflectionUtil.findAllSetters(clazz, propertyName.name, propertyValue, options);
+ List<Method> setters = ReflectionUtil.findAllSetters(clazz, propertyName.name, propertyValue, options, registry);
for (Method setter : setters) {
MethodMember member = new MethodMember(setter);
members.add(member);
@@ -473,7 +480,7 @@
if (options.contains(Option.FIELD_INJECTION)) {
try {
- FieldMember member = new FieldMember(ReflectionUtil.findField(clazz, propertyName.name, propertyValue, options));
+ FieldMember member = new FieldMember(ReflectionUtil.findField(clazz, propertyName.name, propertyValue, options, registry));
members.add(member);
} catch (MissingAccessorException noField) {
if (members.isEmpty()) {
@@ -494,7 +501,7 @@
for (Member member : members) {
// convert the value to type of setter/field
try {
- propertyValue = RecipeHelper.convert(member.getType(), propertyValue, false);
+ propertyValue = RecipeHelper.convert(member.getType(), propertyValue, false, registry);
} catch (Exception e) {
// save off first conversion exception, in case setting failed
if (conversionException == null) {
@@ -582,14 +589,14 @@
Object value;
if (propertyValues.containsKey(name)) {
value = propertyValues.remove(name);
- if (!RecipeHelper.isInstance(type, value) && !RecipeHelper.isConvertable(type, value)) {
+ if (!RecipeHelper.isInstance(type, value) && !RecipeHelper.isConvertable(type, value, registry)) {
throw new ConstructionException("Invalid and non-convertable constructor parameter type: " +
"name=" + name + ", " +
"index=" + i + ", " +
"expected=" + RecipeHelper.toClass(type).getName() + ", " +
"actual=" + (value == null ? "null" : value.getClass().getName()));
}
- value = RecipeHelper.convert(type, value, false);
+ value = RecipeHelper.convert(type, value, false, registry);
} else {
value = getDefaultValue(RecipeHelper.toClass(type));
}
diff --git a/xbean-reflect/src/main/java/org/apache/xbean/recipe/RecipeHelper.java b/xbean-reflect/src/main/java/org/apache/xbean/recipe/RecipeHelper.java
index c1fded0..77224b9 100644
--- a/xbean-reflect/src/main/java/org/apache/xbean/recipe/RecipeHelper.java
+++ b/xbean-reflect/src/main/java/org/apache/xbean/recipe/RecipeHelper.java
@@ -30,6 +30,8 @@
import java.util.List;
import java.util.Map;
+import org.apache.xbean.propertyeditor.Primitives;
+import org.apache.xbean.propertyeditor.PropertyEditorRegistry;
import org.apache.xbean.propertyeditor.PropertyEditors;
/**
@@ -124,12 +126,12 @@
return instance == null || type.isInstance(instance);
}
- public static boolean isConvertable(Type type, Object propertyValue) {
+ public static boolean isConvertable(Type type, Object propertyValue, PropertyEditorRegistry registry) {
if (propertyValue instanceof Recipe) {
Recipe recipe = (Recipe) propertyValue;
return recipe.canCreate(type);
}
- return (propertyValue instanceof String && PropertyEditors.canConvert(toClass(type)))
+ return (propertyValue instanceof String && (registry == null ? PropertyEditors.registry() : registry).findConverter(toClass(type)) != null)
|| (type == String.class && char[].class.isInstance(propertyValue));
}
@@ -138,31 +140,13 @@
if (expected.isPrimitive()) {
// verify actual is the correct wrapper type
- if (expected.equals(boolean.class)) {
- return actual.equals(Boolean.class);
- } else if (expected.equals(char.class)) {
- return actual.equals(Character.class);
- } else if (expected.equals(byte.class)) {
- return actual.equals(Byte.class);
- } else if (expected.equals(short.class)) {
- return actual.equals(Short.class);
- } else if (expected.equals(int.class)) {
- return actual.equals(Integer.class);
- } else if (expected.equals(long.class)) {
- return actual.equals(Long.class);
- } else if (expected.equals(float.class)) {
- return actual.equals(Float.class);
- } else if (expected.equals(double.class)) {
- return actual.equals(Double.class);
- } else {
- throw new AssertionError("Invalid primitve type: " + expected);
- }
+ return actual.equals(Primitives.toWrapper(expected));
}
return expected.isAssignableFrom(actual);
}
- public static Object convert(Type expectedType, Object value, boolean lazyRefAllowed) {
+ public static Object convert(Type expectedType, Object value, boolean lazyRefAllowed, PropertyEditorRegistry registry) {
if (value instanceof Recipe) {
Recipe recipe = (Recipe) value;
value = recipe.create(expectedType, lazyRefAllowed);
@@ -178,7 +162,7 @@
if (value instanceof String && (expectedType != Object.class)) {
String stringValue = (String) value;
- value = PropertyEditors.getValue(expectedType, stringValue);
+ value = (registry == null ? PropertyEditors.registry() : registry).getValue(expectedType, stringValue);
}
return value;
}
@@ -215,9 +199,8 @@
} else if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
return toClass(parameterizedType.getRawType());
- } else {
- return Object.class;
}
+ return Object.class;
}
public static class RecipeComparator implements Comparator<Object> {
diff --git a/xbean-reflect/src/main/java/org/apache/xbean/recipe/ReflectionUtil.java b/xbean-reflect/src/main/java/org/apache/xbean/recipe/ReflectionUtil.java
index d205985..57c465c 100644
--- a/xbean-reflect/src/main/java/org/apache/xbean/recipe/ReflectionUtil.java
+++ b/xbean-reflect/src/main/java/org/apache/xbean/recipe/ReflectionUtil.java
@@ -37,6 +37,8 @@
import static org.apache.xbean.recipe.RecipeHelper.isAssignableFrom;
+import org.apache.xbean.propertyeditor.PropertyEditorRegistry;
+
public final class ReflectionUtil {
private static final class ParameterLoader {
private static ParameterNameLoader PARAMETER_NAME_LOADER;
@@ -65,7 +67,8 @@
}
}
- public static Field findField(Class typeClass, String propertyName, Object propertyValue, Set<Option> options) {
+ public static Field findField(Class typeClass, String propertyName, Object propertyValue, Set<Option> options,
+ PropertyEditorRegistry registry) {
if (typeClass == null) throw new NullPointerException("typeClass is null");
if (propertyName == null) throw new NullPointerException("name is null");
if (propertyName.length() == 0) throw new IllegalArgumentException("name is an empty string");
@@ -135,7 +138,7 @@
}
- if (!RecipeHelper.isInstance(fieldType, propertyValue) && !RecipeHelper.isConvertable(fieldType, propertyValue)) {
+ if (!RecipeHelper.isInstance(fieldType, propertyValue) && !RecipeHelper.isConvertable(fieldType, propertyValue, registry)) {
if (matchLevel < 5) {
matchLevel = 5;
missException = new MissingAccessorException((propertyValue == null ? "null" : propertyValue.getClass().getName()) + " can not be assigned or converted to " +
@@ -229,8 +232,9 @@
return null;
}
- public static Method findSetter(Class typeClass, String propertyName, Object propertyValue, Set<Option> options) {
- List<Method> setters = findAllSetters(typeClass, propertyName, propertyValue, options);
+ public static Method findSetter(Class typeClass, String propertyName, Object propertyValue, Set<Option> options,
+ PropertyEditorRegistry registry) {
+ List<Method> setters = findAllSetters(typeClass, propertyName, propertyValue, options, registry);
return setters.get(0);
}
@@ -244,7 +248,8 @@
* @param options controls which setters are considered valid
* @return the valid setters; never null or empty
*/
- public static List<Method> findAllSetters(Class typeClass, String propertyName, Object propertyValue, Set<Option> options) {
+ public static List<Method> findAllSetters(Class typeClass, String propertyName, Object propertyValue, Set<Option> options,
+ PropertyEditorRegistry registry) {
if (typeClass == null) throw new NullPointerException("typeClass is null");
if (propertyName == null) throw new NullPointerException("name is null");
if (propertyName.length() == 0) throw new IllegalArgumentException("name is an empty string");
@@ -349,7 +354,7 @@
}
- if (!RecipeHelper.isInstance(methodParameterType, propertyValue) && !RecipeHelper.isConvertable(methodParameterType, propertyValue)) {
+ if (!RecipeHelper.isInstance(methodParameterType, propertyValue) && !RecipeHelper.isConvertable(methodParameterType, propertyValue, registry)) {
if (matchLevel < 5) {
matchLevel = 5;
missException = new MissingAccessorException((propertyValue == null ? "null" : propertyValue.getClass().getName()) + " can not be assigned or converted to " +
@@ -396,7 +401,8 @@
}
}
- public static List<Field> findAllFieldsByType(Class typeClass, Object propertyValue, Set<Option> options) {
+ public static List<Field> findAllFieldsByType(Class typeClass, Object propertyValue, Set<Option> options,
+ PropertyEditorRegistry registry) {
if (typeClass == null) throw new NullPointerException("typeClass is null");
if (options == null) options = EnumSet.noneOf(Option.class);
@@ -416,7 +422,7 @@
LinkedList<Field> validFields = new LinkedList<Field>();
for (Field field : fields) {
Class fieldType = field.getType();
- if (RecipeHelper.isInstance(fieldType, propertyValue) || RecipeHelper.isConvertable(fieldType, propertyValue)) {
+ if (RecipeHelper.isInstance(fieldType, propertyValue) || RecipeHelper.isConvertable(fieldType, propertyValue, registry)) {
if (!allowPrivate && !Modifier.isPublic(field.getModifiers())) {
if (matchLevel < 4) {
matchLevel = 4;
@@ -475,7 +481,8 @@
throw new MissingAccessorException(buffer.toString(), -1);
}
}
- public static List<Method> findAllSettersByType(Class typeClass, Object propertyValue, Set<Option> options) {
+ public static List<Method> findAllSettersByType(Class typeClass, Object propertyValue, Set<Option> options,
+ PropertyEditorRegistry registry) {
if (typeClass == null) throw new NullPointerException("typeClass is null");
if (options == null) options = EnumSet.noneOf(Option.class);
@@ -489,7 +496,7 @@
List<Method> methods = new ArrayList<Method>(Arrays.asList(typeClass.getMethods()));
methods.addAll(Arrays.asList(typeClass.getDeclaredMethods()));
for (Method method : methods) {
- if (method.getName().startsWith("set") && method.getParameterTypes().length == 1 && (RecipeHelper.isInstance(method.getParameterTypes()[0], propertyValue) || RecipeHelper.isConvertable(method.getParameterTypes()[0], propertyValue))) {
+ if (method.getName().startsWith("set") && method.getParameterTypes().length == 1 && (RecipeHelper.isInstance(method.getParameterTypes()[0], propertyValue) || RecipeHelper.isConvertable(method.getParameterTypes()[0], propertyValue, registry))) {
if (method.getReturnType() != Void.TYPE) {
if (matchLevel < 2) {
matchLevel = 2;
diff --git a/xbean-reflect/src/test/java/org/apache/xbean/recipe/RecipeHelperTest.java b/xbean-reflect/src/test/java/org/apache/xbean/recipe/RecipeHelperTest.java
index 21efbe6..712acc5 100644
--- a/xbean-reflect/src/test/java/org/apache/xbean/recipe/RecipeHelperTest.java
+++ b/xbean-reflect/src/test/java/org/apache/xbean/recipe/RecipeHelperTest.java
@@ -16,6 +16,7 @@
*/
package org.apache.xbean.recipe;
+import org.apache.xbean.propertyeditor.PropertyEditors;
import org.junit.Test;
import static org.junit.Assert.assertArrayEquals;
@@ -25,13 +26,13 @@
public class RecipeHelperTest {
@Test
public void stringCharArrayIsConvertable() {
- assertTrue(RecipeHelper.isConvertable(char[].class, "foo"));
- assertTrue(RecipeHelper.isConvertable(String.class, "foo".toCharArray()));
+ assertTrue(RecipeHelper.isConvertable(char[].class, "foo", PropertyEditors.registry()));
+ assertTrue(RecipeHelper.isConvertable(String.class, "foo".toCharArray(), PropertyEditors.registry()));
}
@Test
public void stringCharArrayConvert() {
- assertArrayEquals("foo".toCharArray(), char[].class.cast(RecipeHelper.convert(char[].class, "foo", false)));
- assertEquals("foo", RecipeHelper.convert(String.class, "foo".toCharArray(), false));
+ assertArrayEquals("foo".toCharArray(), char[].class.cast(RecipeHelper.convert(char[].class, "foo", false, PropertyEditors.registry())));
+ assertEquals("foo", RecipeHelper.convert(String.class, "foo".toCharArray(), false, PropertyEditors.registry()));
}
}