Moved Spring Web Flow to a top level project
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.collection;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Iterator that combines multiple other iterators. This is a simple implementation
|
||||
* that just maintains a list of iterators which are invoked in sequence untill
|
||||
* all iterators are exhausted.
|
||||
*
|
||||
* @author Erwin Vervaet
|
||||
*/
|
||||
public class CompositeIterator implements Iterator {
|
||||
|
||||
private List iterators = new LinkedList();
|
||||
|
||||
private boolean inUse = false;
|
||||
|
||||
/**
|
||||
* Create a new composite iterator. Add iterators using the {@link #add(Iterator)} method.
|
||||
*/
|
||||
public CompositeIterator() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add given iterator to this composite.
|
||||
*/
|
||||
public void add(Iterator iterator) {
|
||||
Assert.state(!inUse, "You can no longer add iterator to a composite iterator that's already in use");
|
||||
if (iterators.contains(iterator)) {
|
||||
throw new IllegalArgumentException("You cannot add the same iterator twice");
|
||||
}
|
||||
iterators.add(iterator);
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
inUse = true;
|
||||
for (Iterator it = iterators.iterator(); it.hasNext(); ) {
|
||||
if (((Iterator)it.next()).hasNext()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Object next() {
|
||||
inUse = true;
|
||||
for (Iterator it = iterators.iterator(); it.hasNext(); ) {
|
||||
Iterator iterator = (Iterator)it.next();
|
||||
if (iterator.hasNext()) {
|
||||
return iterator.next();
|
||||
}
|
||||
}
|
||||
throw new NoSuchElementException("Exhaused all iterators");
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException("Remove is not supported");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,463 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.collection;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A simple, generic decorator for getting attributes out of a map. May be
|
||||
* instantiated directly or used as a base class as a convenience.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class MapAccessor implements MapAdaptable {
|
||||
|
||||
/**
|
||||
* The target map.
|
||||
*/
|
||||
private Map map;
|
||||
|
||||
/**
|
||||
* Creates a new attribute map accessor.
|
||||
* @param map the map
|
||||
*/
|
||||
public MapAccessor(Map map) {
|
||||
Assert.notNull(map, "The map to decorate is required");
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
// implementing MapAdaptable
|
||||
|
||||
public Map asMap() {
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value in the map, returning the defaultValue if no value was
|
||||
* found.
|
||||
* @param key the key
|
||||
* @param defaultValue the default
|
||||
* @return the attribute value
|
||||
*/
|
||||
public Object get(Object key, Object defaultValue) {
|
||||
if (!map.containsKey(key)) {
|
||||
return defaultValue;
|
||||
}
|
||||
return map.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value in the map, asserting it is of the required type if
|
||||
* present and returning <code>null</code> if not found.
|
||||
* @param key the key
|
||||
* @param requiredType the required type
|
||||
* @return the value
|
||||
* @throws IllegalArgumentException if the key is present but the value is
|
||||
* not of the required type
|
||||
*/
|
||||
public Object get(Object key, Class requiredType) throws IllegalArgumentException {
|
||||
return get(key, requiredType, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value in the map of the specified type, returning the
|
||||
* defaultValue if no value is found.
|
||||
* @param key the key
|
||||
* @param requiredType the required type
|
||||
* @param defaultValue the default
|
||||
* @return the attribute value
|
||||
* @throws IllegalArgumentException if the key is present but the value is
|
||||
* not of the required type
|
||||
*/
|
||||
public Object get(Object key, Class requiredType, Object defaultValue) {
|
||||
if (!map.containsKey(key)) {
|
||||
return defaultValue;
|
||||
}
|
||||
return assertKeyValueOfType(key, requiredType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value in the map, throwing an exception if the attribute is not
|
||||
* present and of the correct type.
|
||||
* @param key the key
|
||||
* @return the value
|
||||
*/
|
||||
public Object getRequired(Object key) throws IllegalArgumentException {
|
||||
assertContainsKey(key);
|
||||
return map.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an value in the map, asserting it is present and of the required
|
||||
* type.
|
||||
* @param key the key
|
||||
* @param requiredType the required type
|
||||
* @return the value
|
||||
*/
|
||||
public Object getRequired(Object key, Class requiredType) throws IllegalArgumentException {
|
||||
assertContainsKey(key);
|
||||
return assertKeyValueOfType(key, requiredType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string value in the map, returning <code>null</code> if no
|
||||
* value was found.
|
||||
* @param key the key
|
||||
* @return the string value
|
||||
* @throws IllegalArgumentException if the key is present but the value is
|
||||
* not a string
|
||||
*/
|
||||
public String getString(Object key) throws IllegalArgumentException {
|
||||
return getString(key, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string value in the map, returning the defaultValue if no value
|
||||
* was found.
|
||||
* @param key the key
|
||||
* @param defaultValue the default
|
||||
* @return the string value
|
||||
* @throws IllegalArgumentException if the key is present but the value is
|
||||
* not a string
|
||||
*/
|
||||
public String getString(Object key, String defaultValue) throws IllegalArgumentException {
|
||||
if (!map.containsKey(key)) {
|
||||
return defaultValue;
|
||||
}
|
||||
return (String)assertKeyValueOfType(key, String.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string value in the map, throwing an exception if the attribute
|
||||
* is not present and of the correct type.
|
||||
* @param key the key
|
||||
* @return the string value
|
||||
* @throws IllegalArgumentException if the key is not present or present but
|
||||
* the value is not a string
|
||||
*/
|
||||
public String getRequiredString(Object key) throws IllegalArgumentException {
|
||||
assertContainsKey(key);
|
||||
return (String)assertKeyValueOfType(key, String.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a collection value in the map, returning <code>null</code> if
|
||||
* no value was found.
|
||||
* @param key the key
|
||||
* @return the collection value
|
||||
* @throws IllegalArgumentException if the key is present but the value is
|
||||
* not a collection
|
||||
*/
|
||||
public Collection getCollection(Object key) throws IllegalArgumentException {
|
||||
if (!map.containsKey(key)) {
|
||||
return null;
|
||||
}
|
||||
return (Collection)assertKeyValueOfType(key, Collection.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a collection value in the map, asserting it is of the required
|
||||
* type if present and returning <code>null</code> if not found.
|
||||
* @param key the key
|
||||
* @return the collection value
|
||||
* @throws IllegalArgumentException if the key is present but the value is
|
||||
* not a collection
|
||||
*/
|
||||
public Collection getCollection(Object key, Class requiredType) throws IllegalArgumentException {
|
||||
if (!map.containsKey(key)) {
|
||||
return null;
|
||||
}
|
||||
assertAssignableTo(Collection.class, requiredType);
|
||||
return (Collection)assertKeyValueOfType(key, requiredType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a collection value in the map, throwing an exception if not
|
||||
* found.
|
||||
* @param key the key
|
||||
* @return the collection value
|
||||
* @throws IllegalArgumentException if the key is not present or present but
|
||||
* the value is not a collection
|
||||
*/
|
||||
public Collection getRequiredCollection(Object key) throws IllegalArgumentException {
|
||||
assertContainsKey(key);
|
||||
return (Collection)assertKeyValueOfType(key, Collection.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a collection value in the map, asserting it is of the required
|
||||
* type if present and throwing an exception if not found.
|
||||
* @param key the key
|
||||
* @return the collection value
|
||||
* @throws IllegalArgumentException if the key is not present or present but
|
||||
* the value is not a collection of the required type
|
||||
*/
|
||||
public Collection getRequiredCollection(Object key, Class requiredType) throws IllegalArgumentException {
|
||||
assertContainsKey(key);
|
||||
assertAssignableTo(Collection.class, requiredType);
|
||||
return (Collection)assertKeyValueOfType(key, requiredType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a array value in the map, asserting it is of the required type if
|
||||
* present and returning <code>null</code> if not found.
|
||||
* @param key the key
|
||||
* @return the array value
|
||||
* @throws IllegalArgumentException if the key is present but the value is
|
||||
* not an array of the required type
|
||||
*/
|
||||
public Object[] getArray(Object key, Class requiredType) throws IllegalArgumentException {
|
||||
assertAssignableTo(Object[].class, requiredType);
|
||||
if (!map.containsKey(key)) {
|
||||
return null;
|
||||
}
|
||||
return (Object[])assertKeyValueOfType(key, requiredType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array value in the map, asserting it is of the required type
|
||||
* if present and throwing an exception if not found.
|
||||
* @param key the key
|
||||
* @return the array value
|
||||
* @throws IllegalArgumentException if the key is not present or present but
|
||||
* the value is not a array of the required type
|
||||
*/
|
||||
public Object[] getRequiredArray(Object key, Class requiredType) throws IllegalArgumentException {
|
||||
assertContainsKey(key);
|
||||
assertAssignableTo(Object[].class, requiredType);
|
||||
return (Object[])assertKeyValueOfType(key, requiredType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a number value in the map that is of the specified type,
|
||||
* returning <code>null</code> if no value was found.
|
||||
* @param key the key
|
||||
* @param requiredType the required number type
|
||||
* @return the numbervalue
|
||||
* @throws IllegalArgumentException if the key is present but the value is
|
||||
* not a number of the required type
|
||||
*/
|
||||
public Number getNumber(Object key, Class requiredType) throws IllegalArgumentException {
|
||||
return getNumber(key, requiredType, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a number attribute value in the map of the specified type,
|
||||
* returning the defaultValue if no value was found.
|
||||
* @param key the attribute name
|
||||
* @return the number value
|
||||
* @param defaultValue the default
|
||||
* @throws IllegalArgumentException if the key is present but the value is
|
||||
* not a number of the required type
|
||||
*/
|
||||
public Number getNumber(Object key, Class requiredType, Number defaultValue) throws IllegalArgumentException {
|
||||
if (!map.containsKey(key)) {
|
||||
return defaultValue;
|
||||
}
|
||||
assertAssignableTo(Number.class, requiredType);
|
||||
return (Number)assertKeyValueOfType(key, requiredType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a number value in the map, throwing an exception if the attribute
|
||||
* is not present and of the correct type.
|
||||
* @param key the key
|
||||
* @return the number value
|
||||
* @throws IllegalArgumentException if the key is not present or present but
|
||||
* the value is not a number of the required type
|
||||
*/
|
||||
public Number getRequiredNumber(Object key, Class requiredType) throws IllegalArgumentException {
|
||||
assertContainsKey(key);
|
||||
return (Number)assertKeyValueOfType(key, requiredType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an integer value in the map, returning <code>null</code> if no
|
||||
* value was found.
|
||||
* @param key the key
|
||||
* @return the integer value
|
||||
* @throws IllegalArgumentException if the key is present but the value is
|
||||
* not an integer
|
||||
*/
|
||||
public Integer getInteger(Object key) throws IllegalArgumentException {
|
||||
return getInteger(key, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an integer value in the map, returning the defaultValue if no
|
||||
* value was found.
|
||||
* @param key the key
|
||||
* @param defaultValue the default
|
||||
* @return the integer value
|
||||
* @throws IllegalArgumentException if the key is present but the value is
|
||||
* not an integer
|
||||
*/
|
||||
public Integer getInteger(Object key, Integer defaultValue) throws IllegalArgumentException {
|
||||
return (Integer)getNumber(key, Integer.class, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an integer value in the map, throwing an exception if the value
|
||||
* is not present and of the correct type.
|
||||
* @param key the attribute name
|
||||
* @return the integer attribute value
|
||||
* @throws IllegalArgumentException if the key is not present or present but
|
||||
* the value is not an integer
|
||||
*/
|
||||
public Integer getRequiredInteger(Object key) throws IllegalArgumentException {
|
||||
return (Integer)getRequiredNumber(key, Integer.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a long value in the map, returning <code>null</code> if no
|
||||
* value was found.
|
||||
* @param key the key
|
||||
* @return the long value
|
||||
* @throws IllegalArgumentException if the key is present but not a long
|
||||
*/
|
||||
public Long getLong(Object key) throws IllegalArgumentException {
|
||||
return getLong(key, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a long value in the map, returning the defaultValue if no value
|
||||
* was found.
|
||||
* @param key the key
|
||||
* @param defaultValue the default
|
||||
* @return the long attribute value
|
||||
* @throws IllegalArgumentException if the key is present but the value is
|
||||
* not a long
|
||||
*/
|
||||
public Long getLong(Object key, Long defaultValue) throws IllegalArgumentException {
|
||||
return (Long)getNumber(key, Long.class, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a long value in the map, throwing an exception if the value is
|
||||
* not present and of the correct type.
|
||||
* @param key the key
|
||||
* @return the long attribute value
|
||||
* @throws IllegalArgumentException if the key is not present or present but
|
||||
* the value is not a long
|
||||
*/
|
||||
public Long getRequiredLong(Object key) throws IllegalArgumentException {
|
||||
return (Long)getRequiredNumber(key, Long.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a boolean value in the map, returning <code>null</code> if no
|
||||
* value was found.
|
||||
* @param key the key
|
||||
* @return the boolean value
|
||||
* @throws IllegalArgumentException if the key is present but the value is
|
||||
* not a boolean
|
||||
*/
|
||||
public Boolean getBoolean(Object key) throws IllegalArgumentException {
|
||||
return getBoolean(key, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a boolean value in the map, returning the defaultValue if no
|
||||
* value was found.
|
||||
* @param key the key
|
||||
* @param defaultValue the default
|
||||
* @return the boolean value
|
||||
* @throws IllegalArgumentException if the key is present but the value is
|
||||
* not a boolean
|
||||
*/
|
||||
public Boolean getBoolean(Object key, Boolean defaultValue) throws IllegalArgumentException {
|
||||
if (!map.containsKey(key)) {
|
||||
return defaultValue;
|
||||
}
|
||||
return (Boolean)assertKeyValueOfType(key, Boolean.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a boolean value in the map, throwing an exception if the value is
|
||||
* not present and of the correct type.
|
||||
* @param key the attribute
|
||||
* @return the boolean value
|
||||
* @throws IllegalArgumentException if the key is not present or present but
|
||||
* the value is not a boolean
|
||||
*/
|
||||
public Boolean getRequiredBoolean(Object key) throws IllegalArgumentException {
|
||||
assertContainsKey(key);
|
||||
return (Boolean)assertKeyValueOfType(key, Boolean.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the attribute is present in the attribute map.
|
||||
* @param key the key
|
||||
* @throws IllegalArgumentException if the key is not present
|
||||
*/
|
||||
public void assertContainsKey(Object key) throws IllegalArgumentException {
|
||||
if (!map.containsKey(key)) {
|
||||
throw new IllegalArgumentException("Required attribute '" + key
|
||||
+ "' is not present in map; attributes present are [" + asMap() + "]");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the attribute is present in the attribute map and of the
|
||||
* required type.
|
||||
* @param key the attribute name
|
||||
* @return true if present and of the required type, false if not present.
|
||||
*/
|
||||
public boolean containsKey(Object key, Class requiredType) throws IllegalArgumentException {
|
||||
if (map.containsKey(key)) {
|
||||
assertKeyValueOfType(key, requiredType);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that value of the mak key is of the required type.
|
||||
* @param key the attribute name
|
||||
* @param requiredType the required attribute value type
|
||||
* @return the attribute value
|
||||
*/
|
||||
public Object assertKeyValueOfType(Object key, Class requiredType) {
|
||||
return assertKeyValueInstanceOf(key, map.get(key), requiredType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the key value is an instance of the required type.
|
||||
* @param key the key
|
||||
* @param value the value
|
||||
* @param requiredType the required type
|
||||
* @return the value
|
||||
*/
|
||||
public Object assertKeyValueInstanceOf(Object key, Object value, Class requiredType) {
|
||||
Assert.notNull(requiredType, "The required type to assert is required");
|
||||
if (!requiredType.isInstance(value)) {
|
||||
throw new IllegalArgumentException("Map key '" + key + "' has value [" + value
|
||||
+ "] that is not of expected type [" + requiredType + "], instead it is of type ["
|
||||
+ (value != null ? value.getClass().getName() : "null") + "]");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private void assertAssignableTo(Class clazz, Class requiredType) {
|
||||
Assert.isTrue(clazz.isAssignableFrom(requiredType), "The provided required type must be assignable to ["
|
||||
+ clazz + "]");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.collection;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* An object whose contents are capable of being exposed as an unmodifiable map.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public interface MapAdaptable {
|
||||
|
||||
/**
|
||||
* Returns this object's contents as a {@link Map}. The returned map may or
|
||||
* may not be modifiable depending on this implementation.
|
||||
* <p>
|
||||
* Warning: this operation may be called frequently; if so care should be
|
||||
* taken so that the map contents (if calculated) be cached as appropriate.
|
||||
* @return the object's contents as a map
|
||||
*/
|
||||
public Map asMap();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.collection;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A simple subinterface of {@link Map} that exposes a mutex that
|
||||
* application code can synchronize on.
|
||||
* <p>
|
||||
* Expected to be implemented by Maps that are backed by shared objects that
|
||||
* require synchronization between multiple threads. An example would be the
|
||||
* HTTP session map.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public interface SharedMap extends Map {
|
||||
|
||||
/**
|
||||
* Returns the shared mutex that may be synchronized on using a
|
||||
* synchronized block. The returned mutex is guaranteed to be non-null.
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* <pre>
|
||||
* synchronized (sharedMap.getMutex()) {
|
||||
* // do synchronized work
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @return the mutex
|
||||
*/
|
||||
public Object getMutex();
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.collection;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
|
||||
/**
|
||||
* A map decorator that implements <code>SharedMap</code>. By default, simply
|
||||
* returns the map itself as the mutex. Subclasses may override to return a
|
||||
* different mutex object.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class SharedMapDecorator implements SharedMap, Serializable {
|
||||
|
||||
/**
|
||||
* The wrapped, target map.
|
||||
*/
|
||||
private Map map;
|
||||
|
||||
/**
|
||||
* Creates a new shared map decorator.
|
||||
* @param map the map that is shared by multiple threads, to be synced
|
||||
*/
|
||||
public SharedMapDecorator(Map map) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
// implementing Map
|
||||
|
||||
public void clear() {
|
||||
map.clear();
|
||||
}
|
||||
|
||||
public boolean containsKey(Object key) {
|
||||
return map.containsKey(key);
|
||||
}
|
||||
|
||||
public boolean containsValue(Object value) {
|
||||
return map.containsValue(value);
|
||||
}
|
||||
|
||||
public Set entrySet() {
|
||||
return map.entrySet();
|
||||
}
|
||||
|
||||
public Object get(Object key) {
|
||||
return map.get(key);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return map.isEmpty();
|
||||
}
|
||||
|
||||
public Set keySet() {
|
||||
return map.keySet();
|
||||
}
|
||||
|
||||
public Object put(Object key, Object value) {
|
||||
return map.put(key, value);
|
||||
}
|
||||
|
||||
public void putAll(Map map) {
|
||||
this.map.putAll(map);
|
||||
}
|
||||
|
||||
public Object remove(Object key) {
|
||||
return map.remove(key);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return map.size();
|
||||
}
|
||||
|
||||
public Collection values() {
|
||||
return map.values();
|
||||
}
|
||||
|
||||
// implementing SharedMap
|
||||
|
||||
public Object getMutex() {
|
||||
return map;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return new ToStringCreator(this).append("map", map).append("mutex", getMutex()).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,285 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.collection;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Base class for map adapters whose keys are String values. Concrete
|
||||
* classes need only implement the abstract hook methods defined by this class.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public abstract class StringKeyedMapAdapter implements Map {
|
||||
|
||||
private Set keySet;
|
||||
|
||||
private Collection values;
|
||||
|
||||
private Set entrySet;
|
||||
|
||||
// implementing Map
|
||||
|
||||
public void clear() {
|
||||
for (Iterator it = getAttributeNames(); it.hasNext();) {
|
||||
removeAttribute((String)it.next());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean containsKey(Object key) {
|
||||
return getAttribute(key.toString()) != null;
|
||||
}
|
||||
|
||||
public boolean containsValue(Object value) {
|
||||
if (value == null) {
|
||||
return false;
|
||||
}
|
||||
for (Iterator it = getAttributeNames(); it.hasNext();) {
|
||||
Object aValue = getAttribute((String)it.next());
|
||||
if (value.equals(aValue)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Set entrySet() {
|
||||
return (entrySet != null) ? entrySet : (entrySet = new EntrySet());
|
||||
}
|
||||
|
||||
public Object get(Object key) {
|
||||
return getAttribute(key.toString());
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return !getAttributeNames().hasNext();
|
||||
}
|
||||
|
||||
public Set keySet() {
|
||||
return (keySet != null) ? keySet : (keySet = new KeySet());
|
||||
}
|
||||
|
||||
public Object put(Object key, Object value) {
|
||||
String stringKey = String.valueOf(key);
|
||||
Object previousValue = getAttribute(stringKey);
|
||||
setAttribute(stringKey, value);
|
||||
return previousValue;
|
||||
}
|
||||
|
||||
public void putAll(Map map) {
|
||||
for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
|
||||
Entry entry = (Entry)it.next();
|
||||
setAttribute(entry.getKey().toString(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
public Object remove(Object key) {
|
||||
String stringKey = key.toString();
|
||||
Object retval = getAttribute(stringKey);
|
||||
removeAttribute(stringKey);
|
||||
return retval;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
int size = 0;
|
||||
for (Iterator it = getAttributeNames(); it.hasNext();) {
|
||||
size++;
|
||||
it.next();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
public Collection values() {
|
||||
return (values != null) ? values : (values = new Values());
|
||||
}
|
||||
|
||||
// hook methods
|
||||
|
||||
/**
|
||||
* Hook method that needs to be implemented by concrete subclasses.
|
||||
* Gets a value associated with a key.
|
||||
* @param key the key to lookup
|
||||
* @return the associated value, or null if none
|
||||
*/
|
||||
protected abstract Object getAttribute(String key);
|
||||
|
||||
/**
|
||||
* Hook method that needs to be implemented by concrete subclasses.
|
||||
* Puts a key-value pair in the map, overwriting any possible earlier
|
||||
* value associated with the same key.
|
||||
* @param key the key to associate the value with
|
||||
* @param value the value to associate with the key
|
||||
*/
|
||||
protected abstract void setAttribute(String key, Object value);
|
||||
|
||||
/**
|
||||
* Hook method that needs to be implemented by concrete subclasses.
|
||||
* Removes a key and its associated value from the map.
|
||||
* @param key the key to remove
|
||||
*/
|
||||
protected abstract void removeAttribute(String key);
|
||||
|
||||
/**
|
||||
* Hook method that needs to be implemented by concrete subclasses.
|
||||
* Returns an enumeration listing all keys known to the map.
|
||||
* @return the key enumeration
|
||||
*/
|
||||
protected abstract Iterator getAttributeNames();
|
||||
|
||||
// internal helper classes
|
||||
|
||||
private abstract class AbstractSet extends java.util.AbstractSet {
|
||||
public boolean isEmpty() {
|
||||
return StringKeyedMapAdapter.this.isEmpty();
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return StringKeyedMapAdapter.this.size();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
StringKeyedMapAdapter.this.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private class KeySet extends AbstractSet {
|
||||
public Iterator iterator() {
|
||||
return new KeyIterator();
|
||||
}
|
||||
|
||||
public boolean contains(Object o) {
|
||||
return StringKeyedMapAdapter.this.containsKey(o);
|
||||
}
|
||||
|
||||
public boolean remove(Object o) {
|
||||
return StringKeyedMapAdapter.this.remove(o) != null;
|
||||
}
|
||||
}
|
||||
|
||||
private class KeyIterator implements Iterator {
|
||||
protected final Iterator it = getAttributeNames();
|
||||
|
||||
protected Object currentKey;
|
||||
|
||||
public void remove() {
|
||||
if (currentKey == null) {
|
||||
throw new NoSuchElementException("You must call next() at least once");
|
||||
}
|
||||
StringKeyedMapAdapter.this.remove(currentKey);
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return it.hasNext();
|
||||
}
|
||||
|
||||
public Object next() {
|
||||
return currentKey = it.next();
|
||||
}
|
||||
}
|
||||
|
||||
private class Values extends AbstractSet {
|
||||
public Iterator iterator() {
|
||||
return new ValuesIterator();
|
||||
}
|
||||
|
||||
public boolean contains(Object o) {
|
||||
return StringKeyedMapAdapter.this.containsValue(o);
|
||||
}
|
||||
|
||||
public boolean remove(Object o) {
|
||||
if (o == null) {
|
||||
return false;
|
||||
}
|
||||
for (Iterator it = iterator(); it.hasNext();) {
|
||||
if (o.equals(it.next())) {
|
||||
it.remove();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private class ValuesIterator extends KeyIterator {
|
||||
public Object next() {
|
||||
super.next();
|
||||
return StringKeyedMapAdapter.this.get(currentKey);
|
||||
}
|
||||
}
|
||||
|
||||
private class EntrySet extends AbstractSet {
|
||||
public Iterator iterator() {
|
||||
return new EntryIterator();
|
||||
}
|
||||
|
||||
public boolean contains(Object o) {
|
||||
if (!(o instanceof Entry)) {
|
||||
return false;
|
||||
}
|
||||
Entry entry = (Entry)o;
|
||||
Object key = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
if (key == null || value == null) {
|
||||
return false;
|
||||
}
|
||||
return value.equals(StringKeyedMapAdapter.this.get(key));
|
||||
}
|
||||
|
||||
public boolean remove(Object o) {
|
||||
if (!(o instanceof Entry)) {
|
||||
return false;
|
||||
}
|
||||
Entry entry = (Entry)o;
|
||||
Object key = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
if (key == null || value == null || !value.equals(StringKeyedMapAdapter.this.get(key))) {
|
||||
return false;
|
||||
}
|
||||
return StringKeyedMapAdapter.this.remove(((Entry)o).getKey()) != null;
|
||||
}
|
||||
}
|
||||
|
||||
private class EntryIterator extends KeyIterator {
|
||||
public Object next() {
|
||||
super.next();
|
||||
return new EntrySetEntry(currentKey);
|
||||
}
|
||||
}
|
||||
|
||||
private class EntrySetEntry implements Entry {
|
||||
private final Object currentKey;
|
||||
|
||||
public EntrySetEntry(Object currentKey) {
|
||||
this.currentKey = currentKey;
|
||||
}
|
||||
|
||||
public Object getKey() {
|
||||
return currentKey;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return StringKeyedMapAdapter.this.get(currentKey);
|
||||
}
|
||||
|
||||
public Object setValue(Object value) {
|
||||
return StringKeyedMapAdapter.this.put(currentKey, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<html>
|
||||
<body>
|
||||
<p>
|
||||
Collection related classes usable by other packages and systems.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.convert;
|
||||
|
||||
/**
|
||||
* A context object with two main responsibities:
|
||||
* <ol>
|
||||
* <li>Exposing information to a converter to influence
|
||||
* a type conversion attempt.
|
||||
* <li>Providing operations for recording progress or
|
||||
* errors during the type conversion process.
|
||||
* </ol>
|
||||
* Empty for now; subclasses may define their own custom context behavior
|
||||
* accessible by a converter with a downcast.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public interface ConversionContext {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.convert;
|
||||
|
||||
import org.springframework.core.NestedRuntimeException;
|
||||
|
||||
/**
|
||||
* Base class for exceptions thrown by the type conversion system.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class ConversionException extends NestedRuntimeException {
|
||||
|
||||
/**
|
||||
* The source type we tried to convert from
|
||||
*/
|
||||
private Class sourceClass;
|
||||
|
||||
/**
|
||||
* The value we tried to convert.
|
||||
*/
|
||||
private Object value;
|
||||
|
||||
/**
|
||||
* The target type we tried to convert to.
|
||||
*/
|
||||
private Class targetClass;
|
||||
|
||||
/**
|
||||
* Creates a new conversion exception.
|
||||
* @param value the value we tried to convert
|
||||
* @param targetClass the target type
|
||||
*/
|
||||
public ConversionException(Object value, Class targetClass) {
|
||||
super("Unable to convert value '" + value + "' of type '" + (value != null ? value.getClass().getName() : null)
|
||||
+ "' to class '" + targetClass.getName() + "'");
|
||||
this.value = value;
|
||||
this.targetClass = targetClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new conversion exception.
|
||||
* @param value the value we tried to convert
|
||||
* @param targetClass the target type
|
||||
* @param cause underlying cause of this exception
|
||||
*/
|
||||
public ConversionException(Object value, Class targetClass, Throwable cause) {
|
||||
super("Unable to convert value '" + value + "' of type '" + (value != null ? value.getClass().getName() : null)
|
||||
+ "' to class '" + targetClass.getName() + "'", cause);
|
||||
this.value = value;
|
||||
this.targetClass = targetClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new conversion exception.
|
||||
* @param value the value we tried to convert
|
||||
* @param targetClass the target type
|
||||
* @param message a descriptive message
|
||||
* @param cause underlying cause of this exception
|
||||
*/
|
||||
public ConversionException(Object value, Class targetClass, String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
this.value = value;
|
||||
this.targetClass = targetClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new conversion exception.
|
||||
* @param sourceClass the source type
|
||||
* @param targetClass the target type
|
||||
* @param message a descriptive message
|
||||
*/
|
||||
public ConversionException(Class sourceClass, Class targetClass, String message) {
|
||||
super(message);
|
||||
this.sourceClass = sourceClass;
|
||||
this.value = null; // not available
|
||||
this.targetClass = targetClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new conversion exception.
|
||||
* @param sourceClass the source type
|
||||
* @param message a descriptive message
|
||||
*/
|
||||
public ConversionException(Class sourceClass, String message) {
|
||||
super(message);
|
||||
this.sourceClass = sourceClass;
|
||||
this.value = null; // not available
|
||||
this.targetClass = null; // not available
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the source type.
|
||||
*/
|
||||
public Class getSourceClass() {
|
||||
return sourceClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value we tried to convert.
|
||||
*/
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the target type.
|
||||
*/
|
||||
public Class getTargetClass() {
|
||||
return targetClass;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.convert;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A command object that is parameterized with the information necessary to
|
||||
* perform a conversion of a source input to a target output.
|
||||
* <p>
|
||||
* Specifically, encapsulates knowledge about how to convert source objects to a
|
||||
* specific target type using a specific converter.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class ConversionExecutor implements Serializable {
|
||||
|
||||
/**
|
||||
* The source value type this executor will attempt to convert from.
|
||||
*/
|
||||
private final Class sourceClass;
|
||||
|
||||
/**
|
||||
* The target value type this executor will attempt to convert to.
|
||||
*/
|
||||
private final Class targetClass;
|
||||
|
||||
/**
|
||||
* The converter that will perform the conversion.
|
||||
*/
|
||||
private final Converter converter;
|
||||
|
||||
/**
|
||||
* Creates a conversion executor.
|
||||
* @param sourceClass the source type that the converter will convert from
|
||||
* @param targetClass the target type that the converter will convert to
|
||||
* @param converter the converter that will perform the conversion
|
||||
*/
|
||||
public ConversionExecutor(Class sourceClass, Class targetClass, Converter converter) {
|
||||
Assert.notNull(sourceClass, "The source class is required");
|
||||
Assert.notNull(targetClass, "The target class is required");
|
||||
Assert.notNull(converter, "The converter is required");
|
||||
this.sourceClass = sourceClass;
|
||||
this.targetClass = targetClass;
|
||||
this.converter = converter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the source class of conversions performed by this executor.
|
||||
* @return the source class
|
||||
*/
|
||||
public Class getSourceClass() {
|
||||
return sourceClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the target class of conversions performed by this executor.
|
||||
* @return the target class
|
||||
*/
|
||||
public Class getTargetClass() {
|
||||
return targetClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the converter that will perform the conversion.
|
||||
* @return the converter
|
||||
*/
|
||||
public Converter getConverter() {
|
||||
return converter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the conversion for the provided source object.
|
||||
* @param source the source object to convert
|
||||
*/
|
||||
public Object execute(Object source) throws ConversionException {
|
||||
return execute(source, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the conversion for the provided source object.
|
||||
* @param source the source object to convert
|
||||
* @param context the conversion context, useful for influencing the
|
||||
* behavior of the converter
|
||||
*/
|
||||
public Object execute(Object source, ConversionContext context) throws ConversionException {
|
||||
if (source != null) {
|
||||
Assert.isInstanceOf(sourceClass, source, "Not of source type: ");
|
||||
}
|
||||
return converter.convert(source, targetClass, context);
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof ConversionExecutor)) {
|
||||
return false;
|
||||
}
|
||||
ConversionExecutor other = (ConversionExecutor)o;
|
||||
return sourceClass.equals(other.sourceClass) && targetClass.equals(other.targetClass);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return sourceClass.hashCode() + targetClass.hashCode();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return new ToStringCreator(this).append("sourceClass", sourceClass).append("targetClass", targetClass)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.convert;
|
||||
|
||||
/**
|
||||
* A service interface for retrieving type conversion executors. The returned
|
||||
* command objects are thread-safe and may be safely cached for use by client
|
||||
* code.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public interface ConversionService {
|
||||
|
||||
/**
|
||||
* Return a conversion executor command object capable of converting source
|
||||
* objects of the specified <code>sourceClass</code> to instances of the
|
||||
* <code>targetClass</code>.
|
||||
* <p>
|
||||
* The returned ConversionExecutor is thread-safe and may safely be cached
|
||||
* for use in client code.
|
||||
* @param sourceClass the source class to convert from
|
||||
* @param targetClass the target class to convert to
|
||||
* @return the executor that can execute instance conversion, never null
|
||||
* @throws ConversionException an exception occured retrieving a converter
|
||||
* for the source-to-target pair
|
||||
*/
|
||||
public ConversionExecutor getConversionExecutor(Class sourceClass, Class targetClass)
|
||||
throws ConversionException;
|
||||
|
||||
/**
|
||||
* Return a conversion executor command object capable of converting source
|
||||
* objects of the specified <code>sourceClass</code> to target objects of
|
||||
* the type associated with the specified alias.
|
||||
* @param sourceClass the sourceClass
|
||||
* @param targetAlias the target alias
|
||||
* @return the conversion executor, or null if the alias cannot be found
|
||||
* @throws ConversionException an exception occured retrieving a converter
|
||||
* for the source-to-target pair
|
||||
*/
|
||||
public ConversionExecutor getConversionExecutorByTargetAlias(Class sourceClass, String targetAlias)
|
||||
throws ConversionException;
|
||||
|
||||
/**
|
||||
* Return all conversion executors capable of converting source objects of
|
||||
* the the specified <code>sourceClass</code>.
|
||||
* @param sourceClass the source class to convert from
|
||||
* @return the matching conversion executors
|
||||
* @throws ConversionException an exception occured retrieving the converters
|
||||
*/
|
||||
public ConversionExecutor[] getConversionExecutorsForSource(Class sourceClass)
|
||||
throws ConversionException;
|
||||
|
||||
/**
|
||||
* Return the class with the specified alias.
|
||||
* @param alias the class alias
|
||||
* @return the class, or null if not aliased
|
||||
* @throws ConversionException when an error occurs looking up the class by alias
|
||||
*/
|
||||
public Class getClassByAlias(String alias) throws ConversionException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.convert;
|
||||
|
||||
/**
|
||||
* A type converter converts objects from one type to another. They may support
|
||||
* conversion of multiple source types to multiple target types.
|
||||
* <p>
|
||||
* Implementations of this interface are thread-safe.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public interface Converter {
|
||||
|
||||
/**
|
||||
* The source classes this converter can convert from.
|
||||
* @return the supported source classes
|
||||
*/
|
||||
public Class[] getSourceClasses();
|
||||
|
||||
/**
|
||||
* The target classes this converter can convert to.
|
||||
* @return the supported target classes
|
||||
*/
|
||||
public Class[] getTargetClasses();
|
||||
|
||||
/**
|
||||
* Convert the provided source object argument to an instance of the
|
||||
* specified target class.
|
||||
* @param source the source object to convert, its class must be one of the
|
||||
* supported <code>sourceClasses</code>
|
||||
* @param targetClass the target class to convert the source to, must be one
|
||||
* of the supported <code>targetClasses</code>
|
||||
* @param context an optional conversion context that may be used to
|
||||
* influence the conversion process
|
||||
* @return the converted object, an instance of the target type
|
||||
* @throws ConversionException an exception occured during the conversion
|
||||
*/
|
||||
public Object convert(Object source, Class targetClass, ConversionContext context) throws ConversionException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<html>
|
||||
<body>
|
||||
<p>
|
||||
Core services for converting objects from one type to another.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.convert.support;
|
||||
|
||||
import org.springframework.binding.convert.ConversionContext;
|
||||
import org.springframework.binding.convert.ConversionException;
|
||||
import org.springframework.binding.convert.Converter;
|
||||
|
||||
/**
|
||||
* Base class for converters provided as a convenience to implementors.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public abstract class AbstractConverter implements Converter {
|
||||
|
||||
/**
|
||||
* Convenience convert method that converts the provided source to the first
|
||||
* target object supported by this converter. Useful when a converter only
|
||||
* supports conversion to a single target.
|
||||
* @param source the source to convert
|
||||
* @return the converted object
|
||||
* @throws ConversionException an exception occured converting the source
|
||||
* value
|
||||
*/
|
||||
public Object convert(Object source) throws ConversionException {
|
||||
return convert(source, getTargetClasses()[0], null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience convert method that converts the provided source to the
|
||||
* target class specified with an empty conversion context.
|
||||
* @param source the source to convert
|
||||
* @param targetClass the target class to convert the source to, must be one
|
||||
* of the supported <code>targetClasses</code>
|
||||
* @return the converted object
|
||||
* @throws ConversionException an exception occured converting the source
|
||||
* value
|
||||
*/
|
||||
public Object convert(Object source, Class targetClass) throws ConversionException {
|
||||
return convert(source, targetClass, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience convert method that converts the provided source to the first
|
||||
* target object supported by this converter. Useful when a converter only
|
||||
* supports conversion to a single target.
|
||||
* @param source the source to convert
|
||||
* @param context the conversion context, useful for influencing the
|
||||
* behavior of the converter
|
||||
* @return the converted object
|
||||
* @throws ConversionException an exception occured converting the source
|
||||
* value
|
||||
*/
|
||||
public Object convert(Object source, ConversionContext context) throws ConversionException {
|
||||
return convert(source, getTargetClasses()[0], context);
|
||||
}
|
||||
|
||||
public Object convert(Object source, Class targetClass, ConversionContext context) throws ConversionException {
|
||||
try {
|
||||
return doConvert(source, targetClass, context);
|
||||
}
|
||||
catch (ConversionException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable e) {
|
||||
// wrap in a ConversionException
|
||||
if (targetClass == null) {
|
||||
targetClass = getTargetClasses()[0];
|
||||
}
|
||||
throw new ConversionException(source, targetClass, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method subclasses should override to actually perform the type
|
||||
* conversion.
|
||||
* @param source the source to convert from
|
||||
* @param targetClass the target type to convert to
|
||||
* @param context an optional conversion context that may be used to
|
||||
* influence the conversion process, could be null
|
||||
* @return the converted source value
|
||||
* @throws Exception an exception occured, will be wrapped in a conversion
|
||||
* exception if necessary
|
||||
*/
|
||||
protected abstract Object doConvert(Object source, Class targetClass, ConversionContext context) throws Exception;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.convert.support;
|
||||
|
||||
import org.springframework.binding.format.FormatterFactory;
|
||||
|
||||
/**
|
||||
* A converter that delegates to a formatter to perform the conversion.
|
||||
* Formatters are typically not thread safe, so we use a FormatterFactory that
|
||||
* is expected to provide us with thread-safe instances as necessary.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public abstract class AbstractFormattingConverter extends AbstractConverter {
|
||||
|
||||
/**
|
||||
* The formatter factory.
|
||||
*/
|
||||
private FormatterFactory formatterFactory;
|
||||
|
||||
/**
|
||||
* Creates a new converter that delegates to a formatter.
|
||||
* @param formatterFactory the factory to use
|
||||
*/
|
||||
protected AbstractFormattingConverter(FormatterFactory formatterFactory) {
|
||||
setFormatterFactory(formatterFactory);
|
||||
}
|
||||
|
||||
protected FormatterFactory getFormatterFactory() {
|
||||
return formatterFactory;
|
||||
}
|
||||
|
||||
public void setFormatterFactory(FormatterFactory formatterSource) {
|
||||
this.formatterFactory = formatterSource;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.convert.support;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.binding.convert.ConversionException;
|
||||
import org.springframework.binding.convert.ConversionExecutor;
|
||||
import org.springframework.binding.convert.ConversionService;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A conversion service that delegates to an ordered chain of other conversion
|
||||
* services. The first correct reply received from a conversion service in
|
||||
* the chain is returned to the caller.
|
||||
*
|
||||
* @author Erwin Vervaet
|
||||
*/
|
||||
public class CompositeConversionService implements ConversionService {
|
||||
|
||||
private ConversionService[] chain;
|
||||
|
||||
/**
|
||||
* Create a new composite conversion service.
|
||||
* @param conversionServices the conversion services in the chain
|
||||
*/
|
||||
public CompositeConversionService(ConversionService[] conversionServices) {
|
||||
Assert.notNull(conversionServices, "The conversion services chain is required");
|
||||
this.chain = conversionServices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the conversion services in the chain managed by this
|
||||
* composite conversion service.
|
||||
*/
|
||||
public ConversionService[] getConversionServices() {
|
||||
return chain;
|
||||
}
|
||||
|
||||
public ConversionExecutor getConversionExecutor(Class sourceClass, Class targetClass)
|
||||
throws ConversionException {
|
||||
for (int i = 0; i < chain.length; i++) {
|
||||
try {
|
||||
return chain[i].getConversionExecutor(sourceClass, targetClass);
|
||||
}
|
||||
catch (ConversionException e) {
|
||||
// ignore and try the next conversion service in the chain
|
||||
}
|
||||
}
|
||||
throw new ConversionException(sourceClass, targetClass,
|
||||
"No converter registered to convert from sourceClass '" + sourceClass +
|
||||
"' to target class '" + targetClass + "'");
|
||||
}
|
||||
|
||||
public ConversionExecutor getConversionExecutorByTargetAlias(Class sourceClass, String targetAlias)
|
||||
throws ConversionException {
|
||||
boolean exceptionThrown = false;
|
||||
for (int i = 0; i < chain.length; i++) {
|
||||
try {
|
||||
ConversionExecutor res = chain[i].getConversionExecutorByTargetAlias(sourceClass, targetAlias);
|
||||
if (res != null) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
catch (ConversionException e) {
|
||||
exceptionThrown = true;
|
||||
}
|
||||
}
|
||||
if (exceptionThrown) {
|
||||
throw new ConversionException(sourceClass,
|
||||
"No converter registered to convert from sourceClass '" + sourceClass +
|
||||
"' to aliased target type '" + targetAlias + "'");
|
||||
}
|
||||
else {
|
||||
// alias was not recognized by any conversion service in the chain
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public ConversionExecutor[] getConversionExecutorsForSource(Class sourceClass)
|
||||
throws ConversionException {
|
||||
Set executors = new HashSet();
|
||||
for (int i = 0; i < chain.length; i++) {
|
||||
executors.addAll(Arrays.asList(chain[i].getConversionExecutorsForSource(sourceClass)));
|
||||
}
|
||||
return (ConversionExecutor[])executors.toArray(new ConversionExecutor[executors.size()]);
|
||||
}
|
||||
|
||||
public Class getClassByAlias(String alias) throws ConversionException {
|
||||
for (int i = 0; i < chain.length; i++) {
|
||||
try {
|
||||
Class res = chain[i].getClassByAlias(alias);
|
||||
if (res != null) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
catch (ConversionException e) {
|
||||
// ignore and try the next conversion service in the chain
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.convert.support;
|
||||
|
||||
import org.springframework.binding.convert.ConversionService;
|
||||
|
||||
/**
|
||||
* Marker interface that denotes an object has a dependency on a conversion
|
||||
* service that is expected to be fulfilled.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public interface ConversionServiceAware {
|
||||
|
||||
/**
|
||||
* Set the conversion service this object should be made aware of (as it
|
||||
* presumably depends on it).
|
||||
*
|
||||
* @param conversionService the conversion service
|
||||
*/
|
||||
public void setConversionService(ConversionService conversionService);
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.convert.support;
|
||||
|
||||
import org.springframework.binding.convert.ConversionExecutor;
|
||||
import org.springframework.binding.convert.ConversionService;
|
||||
import org.springframework.binding.expression.Expression;
|
||||
|
||||
/**
|
||||
* Base class for converters that use other converters to convert things, thus
|
||||
* they are conversion-service aware.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public abstract class ConversionServiceAwareConverter extends AbstractConverter implements ConversionServiceAware {
|
||||
|
||||
/**
|
||||
* The conversion service this converter is aware of.
|
||||
*/
|
||||
private ConversionService conversionService;
|
||||
|
||||
/**
|
||||
* Default constructor, expectes to conversion service to be injected
|
||||
* using {@link #setConversionService(ConversionService)}.
|
||||
*/
|
||||
protected ConversionServiceAwareConverter() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a converter using given conversion service.
|
||||
*/
|
||||
protected ConversionServiceAwareConverter(ConversionService conversionService) {
|
||||
setConversionService(conversionService);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the conversion service used.
|
||||
*/
|
||||
public ConversionService getConversionService() {
|
||||
if (conversionService == null) {
|
||||
throw new IllegalStateException("Conversion service not yet set: set it first before calling this method");
|
||||
}
|
||||
return conversionService;
|
||||
}
|
||||
|
||||
public void setConversionService(ConversionService conversionService) {
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a conversion executor capable of converting string objects to the
|
||||
* specified target class.
|
||||
* @param targetClass the target class
|
||||
* @return the conversion executor, never null
|
||||
*/
|
||||
protected ConversionExecutor fromStringTo(Class targetClass) {
|
||||
return getConversionService().getConversionExecutor(String.class, targetClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a conversion executor capable of converting string objects to the
|
||||
* target class aliased by the provided alias.
|
||||
* @param targetAlias the target class alias, e.g "long" or "float"
|
||||
* @return the conversion executor, or <code>null</code> if no suitable
|
||||
* converter exists for alias
|
||||
*/
|
||||
protected ConversionExecutor fromStringToAliased(String targetAlias) {
|
||||
return getConversionService().getConversionExecutorByTargetAlias(String.class, targetAlias);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a conversion executor capable of converting objects from one
|
||||
* class to another.
|
||||
* @param sourceClass the source class to convert from
|
||||
* @param targetClass the target class to convert to
|
||||
* @return the conversion executor, never null
|
||||
*/
|
||||
protected ConversionExecutor converterFor(Class sourceClass, Class targetClass) {
|
||||
return getConversionService().getConversionExecutor(sourceClass, targetClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper that parsers the given expression string into an expression, using
|
||||
* the installed String->Expression converter.
|
||||
* @param expressionString the expression string to parse
|
||||
* @return the parsed, evaluatable expression
|
||||
*/
|
||||
protected Expression parseExpression(String expressionString) {
|
||||
return (Expression)fromStringTo(Expression.class).execute(expressionString);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.convert.support;
|
||||
|
||||
import java.beans.PropertyEditorSupport;
|
||||
|
||||
import org.springframework.binding.convert.ConversionExecutor;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Adapts a Converter to the PropertyEditor interface.
|
||||
* <p>
|
||||
* Note: with a converter, only forward conversion from-string-to-value is
|
||||
* supported. Value-to-string conversion is not supported. If you need this
|
||||
* capability, use a Formatter with a FormatterPropertyEditor adapter.
|
||||
*
|
||||
* @see org.springframework.binding.format.Formatter
|
||||
* @see org.springframework.binding.format.support.FormatterPropertyEditor
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class ConverterPropertyEditorAdapter extends PropertyEditorSupport {
|
||||
|
||||
private ConversionExecutor conversionExecutor;
|
||||
|
||||
/**
|
||||
* Adapt given conversion executor to the PropertyEditor contract.
|
||||
*/
|
||||
public ConverterPropertyEditorAdapter(ConversionExecutor conversionExecutor) {
|
||||
Assert.notNull(conversionExecutor, "A conversion executor is required");
|
||||
Assert.isTrue(conversionExecutor.getSourceClass().equals(String.class),
|
||||
"A string conversion executor is required");
|
||||
this.conversionExecutor = conversionExecutor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type strings will be converted to.
|
||||
*/
|
||||
public Class getTargetClass() {
|
||||
return conversionExecutor.getTargetClass();
|
||||
}
|
||||
|
||||
public void setAsText(String text) throws IllegalArgumentException {
|
||||
setValue(conversionExecutor.execute(text));
|
||||
}
|
||||
|
||||
public String getAsText() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2002-2005 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.convert.support;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.binding.convert.ConversionExecutor;
|
||||
import org.springframework.binding.convert.ConversionService;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Registers all 'from string' converters known to a conversion service with
|
||||
* a Spring bean factory.
|
||||
* <p>
|
||||
* Acts as bean factory post processor, registering property editor adapters for
|
||||
* each supported conversion with a <code>java.lang.String sourceClass</code>.
|
||||
* This makes for very convenient use with the Spring container.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class CustomConverterConfigurer implements BeanFactoryPostProcessor, InitializingBean {
|
||||
|
||||
private ConversionService conversionService;
|
||||
|
||||
/**
|
||||
* Create a new configurer.
|
||||
* @param conversionService the conversion service to take converters from
|
||||
*/
|
||||
public void setConversionService(ConversionService conversionService) {
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(conversionService, "The conversion service is required");
|
||||
}
|
||||
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
ConversionExecutor[] executors = conversionService.getConversionExecutorsForSource(String.class);
|
||||
for (int i = 0; i < executors.length; i++) {
|
||||
ConverterPropertyEditorAdapter editor = new ConverterPropertyEditorAdapter(executors[i]);
|
||||
beanFactory.registerCustomEditor(editor.getTargetClass(), editor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.convert.support;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.springframework.binding.format.support.SimpleFormatterFactory;
|
||||
import org.springframework.core.enums.LabeledEnum;
|
||||
|
||||
/**
|
||||
* Default, local implementation of a conversion service. Will automatically
|
||||
* register <i>from string</i> converters for a number of standard Java
|
||||
* types like Class, Number, Boolean and so on.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class DefaultConversionService extends GenericConversionService {
|
||||
|
||||
/**
|
||||
* Creates a new default conversion service, installing the default
|
||||
* converters.
|
||||
*/
|
||||
public DefaultConversionService() {
|
||||
addDefaultConverters();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all default converters to the conversion service.
|
||||
*/
|
||||
protected void addDefaultConverters() {
|
||||
addConverter(new TextToClass());
|
||||
addConverter(new TextToNumber(new SimpleFormatterFactory()));
|
||||
addConverter(new TextToBoolean());
|
||||
addConverter(new TextToLabeledEnum());
|
||||
addDefaultAlias(String.class);
|
||||
addDefaultAlias(Short.class);
|
||||
addDefaultAlias(Integer.class);
|
||||
addAlias("int", Integer.class);
|
||||
addDefaultAlias(Byte.class);
|
||||
addDefaultAlias(Long.class);
|
||||
addDefaultAlias(Float.class);
|
||||
addDefaultAlias(Double.class);
|
||||
addDefaultAlias(BigInteger.class);
|
||||
addDefaultAlias(BigDecimal.class);
|
||||
addDefaultAlias(Boolean.class);
|
||||
addDefaultAlias(Class.class);
|
||||
addDefaultAlias(LabeledEnum.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.convert.support;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.binding.convert.ConversionException;
|
||||
import org.springframework.binding.convert.ConversionExecutor;
|
||||
import org.springframework.binding.convert.ConversionService;
|
||||
import org.springframework.binding.convert.Converter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Base implementation of a conversion service. Initially empty, e.g. no converters
|
||||
* are registered by default.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class GenericConversionService implements ConversionService {
|
||||
|
||||
/**
|
||||
* An indexed map of converters. Each entry key is a source class that can
|
||||
* be converted from, and each entry value is a map of target classes that
|
||||
* can be convertered to, ultimately mapping to a specific converter that
|
||||
* can perform the source->target conversion.
|
||||
*/
|
||||
private Map sourceClassConverters = new HashMap();
|
||||
|
||||
/**
|
||||
* A map of string aliases to convertible classes. Allows lookup of
|
||||
* converters by alias.
|
||||
*/
|
||||
private Map aliasMap = new HashMap();
|
||||
|
||||
/**
|
||||
* An optional parent conversion service.
|
||||
*/
|
||||
private ConversionService parent;
|
||||
|
||||
/**
|
||||
* Returns the parent of this conversion service. Could be null.
|
||||
*/
|
||||
public ConversionService getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the parent of this conversion service. This is optional.
|
||||
*/
|
||||
public void setParent(ConversionService parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add given converter to this conversion service. If the converter is
|
||||
* {@link ConversionServiceAware}, it will get the conversion service
|
||||
* injected.
|
||||
*/
|
||||
public void addConverter(Converter converter) {
|
||||
Class[] sourceClasses = converter.getSourceClasses();
|
||||
Class[] targetClasses = converter.getTargetClasses();
|
||||
for (int i = 0; i < sourceClasses.length; i++) {
|
||||
Class sourceClass = sourceClasses[i];
|
||||
Map sourceMap = (Map)sourceClassConverters.get(sourceClass);
|
||||
if (sourceMap == null) {
|
||||
sourceMap = new HashMap();
|
||||
sourceClassConverters.put(sourceClass, sourceMap);
|
||||
}
|
||||
for (int j = 0; j < targetClasses.length; j++) {
|
||||
Class targetClass = targetClasses[j];
|
||||
sourceMap.put(targetClass, converter);
|
||||
}
|
||||
}
|
||||
if (converter instanceof ConversionServiceAware) {
|
||||
((ConversionServiceAware)converter).setConversionService(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all given converters. If the converters are
|
||||
* {@link ConversionServiceAware}, they will get the conversion service
|
||||
* injected.
|
||||
*/
|
||||
public void addConverters(Converter[] converters) {
|
||||
for (int i = 0; i < converters.length; i++) {
|
||||
addConverter(converters[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add given converter with an alias to the conversion service. If the
|
||||
* converter is {@link ConversionServiceAware}, it will get the conversion
|
||||
* service injected.
|
||||
*/
|
||||
public void addConverter(Converter converter, String alias) {
|
||||
aliasMap.put(alias, converter);
|
||||
addConverter(converter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an alias for given target type.
|
||||
*/
|
||||
public void addAlias(String alias, Class targetType) {
|
||||
aliasMap.put(alias, targetType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a conventions based alias for given target type. For instance,
|
||||
* "java.lang.Boolean" will get the "boolean" alias.
|
||||
*/
|
||||
public void addDefaultAlias(Class targetType) {
|
||||
addAlias(StringUtils.uncapitalize(ClassUtils.getShortName(targetType)), targetType);
|
||||
}
|
||||
|
||||
public ConversionExecutor getConversionExecutor(Class sourceClass, Class targetClass) throws ConversionException {
|
||||
Assert.notNull(sourceClass, "The source class to convert from is required");
|
||||
Assert.notNull(targetClass, "The target class to convert to is required");
|
||||
if (this.sourceClassConverters == null || this.sourceClassConverters.isEmpty()) {
|
||||
throw new IllegalStateException("No converters have been added to this service's registry");
|
||||
}
|
||||
if (sourceClass.equals(targetClass)) {
|
||||
return new ConversionExecutor(sourceClass, targetClass, new NoOpConverter(sourceClass, targetClass));
|
||||
}
|
||||
Map sourceTargetConverters = findConvertersForSource(sourceClass);
|
||||
Converter converter = findTargetConverter(sourceTargetConverters, targetClass);
|
||||
if (converter != null) {
|
||||
// we found a converter
|
||||
return new ConversionExecutor(sourceClass, targetClass, converter);
|
||||
}
|
||||
else {
|
||||
if (parent != null) {
|
||||
// try the parent
|
||||
return parent.getConversionExecutor(sourceClass, targetClass);
|
||||
}
|
||||
else {
|
||||
throw new ConversionException(sourceClass, targetClass,
|
||||
"No converter registered to convert from sourceClass '" + sourceClass +
|
||||
"' to target class '" + targetClass + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ConversionExecutor getConversionExecutorByTargetAlias(Class sourceClass, String alias)
|
||||
throws IllegalArgumentException {
|
||||
Assert.notNull(sourceClass, "The source class to convert from is required");
|
||||
Assert.hasText(alias, "The target alias is required and must either be a type alias (e.g 'boolean') "
|
||||
+ "or a generic converter alias (e.g. 'bean') ");
|
||||
Object targetType = aliasMap.get(alias);
|
||||
if (targetType == null) {
|
||||
if (parent != null) {
|
||||
// try the parent
|
||||
return parent.getConversionExecutorByTargetAlias(sourceClass, alias);
|
||||
}
|
||||
else {
|
||||
// not aliased
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else if (targetType instanceof Class) {
|
||||
return getConversionExecutor(sourceClass, (Class)targetType);
|
||||
}
|
||||
else {
|
||||
Assert.isInstanceOf(Converter.class, targetType, "Not a converter: ");
|
||||
Converter conv = (Converter)targetType;
|
||||
return new ConversionExecutor(sourceClass, Object.class, conv);
|
||||
}
|
||||
}
|
||||
|
||||
public ConversionExecutor[] getConversionExecutorsForSource(Class sourceClass) {
|
||||
Assert.notNull(sourceClass, "The source class to convert from is required");
|
||||
Map sourceTargetConverters = findConvertersForSource(sourceClass);
|
||||
if (sourceTargetConverters.isEmpty()) {
|
||||
if (parent != null) {
|
||||
// use the parent
|
||||
return parent.getConversionExecutorsForSource(sourceClass);
|
||||
}
|
||||
else {
|
||||
// no converters for source class
|
||||
return new ConversionExecutor[0];
|
||||
}
|
||||
}
|
||||
else {
|
||||
Set executors = new HashSet();
|
||||
if (parent != null) {
|
||||
executors.addAll(Arrays.asList(parent.getConversionExecutorsForSource(sourceClass)));
|
||||
}
|
||||
Iterator it = sourceTargetConverters.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry entry = (Map.Entry)it.next();
|
||||
executors.add(new ConversionExecutor(sourceClass, (Class)entry.getKey(), (Converter)entry.getValue()));
|
||||
}
|
||||
return (ConversionExecutor[])executors.toArray(new ConversionExecutor[executors.size()]);
|
||||
}
|
||||
}
|
||||
|
||||
public Class getClassByAlias(String alias) {
|
||||
Assert.hasText(alias, "The alias is required and must be a type alias (e.g 'boolean')");
|
||||
Object clazz = aliasMap.get(alias);
|
||||
if (clazz != null) {
|
||||
Assert.isInstanceOf(Class.class, clazz, "Not a Class alias '" + alias + "': ");
|
||||
return (Class)clazz;
|
||||
}
|
||||
else {
|
||||
if (parent != null) {
|
||||
// try parent service
|
||||
return parent.getClassByAlias(alias);
|
||||
}
|
||||
else {
|
||||
// alias does not index a class, return null
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// internal helpers
|
||||
|
||||
private Map findConvertersForSource(Class sourceClass) {
|
||||
LinkedList classQueue = new LinkedList();
|
||||
classQueue.addFirst(sourceClass);
|
||||
while (!classQueue.isEmpty()) {
|
||||
sourceClass = (Class)classQueue.removeLast();
|
||||
Map sourceTargetConverters = (Map)sourceClassConverters.get(sourceClass);
|
||||
if (sourceTargetConverters != null && !sourceTargetConverters.isEmpty()) {
|
||||
return sourceTargetConverters;
|
||||
}
|
||||
if (!sourceClass.isInterface() && (sourceClass.getSuperclass() != null)) {
|
||||
classQueue.addFirst(sourceClass.getSuperclass());
|
||||
}
|
||||
// queue up source class's implemented interfaces.
|
||||
Class[] interfaces = sourceClass.getInterfaces();
|
||||
for (int i = 0; i < interfaces.length; i++) {
|
||||
classQueue.addFirst(interfaces[i]);
|
||||
}
|
||||
}
|
||||
return Collections.EMPTY_MAP;
|
||||
}
|
||||
|
||||
private Converter findTargetConverter(Map sourceTargetConverters, Class targetClass) {
|
||||
LinkedList classQueue = new LinkedList();
|
||||
classQueue.addFirst(targetClass);
|
||||
while (!classQueue.isEmpty()) {
|
||||
targetClass = (Class)classQueue.removeLast();
|
||||
Converter converter = (Converter)sourceTargetConverters.get(targetClass);
|
||||
if (converter != null) {
|
||||
return converter;
|
||||
}
|
||||
if (!targetClass.isInterface() && (targetClass.getSuperclass() != null)) {
|
||||
classQueue.addFirst(targetClass.getSuperclass());
|
||||
}
|
||||
// queue up target class's implemented interfaces.
|
||||
Class[] interfaces = targetClass.getInterfaces();
|
||||
for (int i = 0; i < interfaces.length; i++) {
|
||||
classQueue.addFirst(interfaces[i]);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// subclassing support
|
||||
|
||||
/**
|
||||
* Returns an indexed map of converters. Each entry key is a source class that
|
||||
* can be converted from, and each entry value is a map of target classes that
|
||||
* can be convertered to, ultimately mapping to a specific converter that can
|
||||
* perform the source->target conversion.
|
||||
*/
|
||||
protected Map getSourceClassConverters() {
|
||||
return sourceClassConverters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a map of known aliases. Each entry key is a String alias and the
|
||||
* associated value is either a target class or a converter.
|
||||
*/
|
||||
protected Map getAliasMap() {
|
||||
return aliasMap;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.convert.support;
|
||||
|
||||
import org.springframework.binding.convert.ConversionContext;
|
||||
|
||||
/**
|
||||
* Package private converter that is a "no op".
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
class NoOpConverter extends AbstractConverter {
|
||||
|
||||
private Class sourceClass;
|
||||
|
||||
private Class targetClass;
|
||||
|
||||
/**
|
||||
* Create a "no op" converter from given source to given target class.
|
||||
*/
|
||||
public NoOpConverter(Class sourceClass, Class targetClass) {
|
||||
this.sourceClass = sourceClass;
|
||||
this.targetClass = targetClass;
|
||||
}
|
||||
|
||||
protected Object doConvert(Object source, Class targetClass, ConversionContext context) throws Exception {
|
||||
return source;
|
||||
}
|
||||
|
||||
public Class[] getSourceClasses() {
|
||||
return new Class[] { sourceClass };
|
||||
}
|
||||
|
||||
public Class[] getTargetClasses() {
|
||||
return new Class[] { targetClass };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.convert.support;
|
||||
|
||||
import org.springframework.binding.convert.ConversionContext;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Converts a textual representation of a boolean object to a <code>Boolean</code>
|
||||
* instance.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class TextToBoolean extends AbstractConverter {
|
||||
|
||||
private static final String VALUE_TRUE = "true";
|
||||
|
||||
private static final String VALUE_FALSE = "false";
|
||||
|
||||
private static final String VALUE_ON = "on";
|
||||
|
||||
private static final String VALUE_OFF = "off";
|
||||
|
||||
private static final String VALUE_YES = "yes";
|
||||
|
||||
private static final String VALUE_NO = "no";
|
||||
|
||||
private static final String VALUE_1 = "1";
|
||||
|
||||
private static final String VALUE_0 = "0";
|
||||
|
||||
private String trueString;
|
||||
|
||||
private String falseString;
|
||||
|
||||
/**
|
||||
* Default constructor. No special true or false strings are considered.
|
||||
*/
|
||||
public TextToBoolean() {
|
||||
this(null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a text to boolean converter. Take given <i>special</i> string representations
|
||||
* of true and false into account.
|
||||
* @param trueString special true string to consider
|
||||
* @param falseString special false string to consider
|
||||
*/
|
||||
public TextToBoolean(String trueString, String falseString) {
|
||||
this.trueString = trueString;
|
||||
this.falseString = falseString;
|
||||
}
|
||||
|
||||
public Class[] getSourceClasses() {
|
||||
return new Class[] { String.class };
|
||||
}
|
||||
|
||||
public Class[] getTargetClasses() {
|
||||
return new Class[] { Boolean.class };
|
||||
}
|
||||
|
||||
protected Object doConvert(Object source, Class targetClass, ConversionContext context) throws Exception {
|
||||
String text = (String)source;
|
||||
if (!StringUtils.hasText(text)) {
|
||||
return null;
|
||||
}
|
||||
else if (this.trueString != null && text.equalsIgnoreCase(this.trueString)) {
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
else if (this.falseString != null && text.equalsIgnoreCase(this.falseString)) {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
else if (this.trueString == null
|
||||
&& (text.equalsIgnoreCase(VALUE_TRUE) || text.equalsIgnoreCase(VALUE_ON)
|
||||
|| text.equalsIgnoreCase(VALUE_YES) || text.equals(VALUE_1))) {
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
else if (this.falseString == null
|
||||
&& (text.equalsIgnoreCase(VALUE_FALSE) || text.equalsIgnoreCase(VALUE_OFF)
|
||||
|| text.equalsIgnoreCase(VALUE_NO) || text.equals(VALUE_0))) {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Invalid boolean value [" + text + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.convert.support;
|
||||
|
||||
import org.springframework.binding.convert.ConversionContext;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Converts a textual representation of a class object to a <code>Class</code>
|
||||
* instance.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class TextToClass extends ConversionServiceAwareConverter {
|
||||
|
||||
private static final String ALIAS_PREFIX = "type:";
|
||||
|
||||
private static final String CLASS_PREFIX = "class:";
|
||||
|
||||
public Class[] getSourceClasses() {
|
||||
return new Class[] { String.class };
|
||||
}
|
||||
|
||||
public Class[] getTargetClasses() {
|
||||
return new Class[] { Class.class };
|
||||
}
|
||||
|
||||
protected Object doConvert(Object source, Class targetClass, ConversionContext context) throws Exception {
|
||||
String text = (String)source;
|
||||
if (StringUtils.hasText(text)) {
|
||||
String classNameOrAlias = text.trim();
|
||||
if (classNameOrAlias.startsWith(CLASS_PREFIX)) {
|
||||
return ClassUtils.forName(text.substring(CLASS_PREFIX.length()));
|
||||
}
|
||||
else if (classNameOrAlias.startsWith(ALIAS_PREFIX)) {
|
||||
String alias = text.substring(ALIAS_PREFIX.length());
|
||||
Class clazz = getConversionService().getClassByAlias(alias);
|
||||
Assert.notNull(clazz, "No class found associated with type alias '" + alias + "'");
|
||||
return clazz;
|
||||
}
|
||||
else {
|
||||
// try first an aliased based lookup
|
||||
if (getConversionService() != null) {
|
||||
Class aliasedClass = getConversionService().getClassByAlias(text);
|
||||
if (aliasedClass != null) {
|
||||
return aliasedClass;
|
||||
}
|
||||
}
|
||||
// treat as a class name
|
||||
return ClassUtils.forName(classNameOrAlias);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.convert.support;
|
||||
|
||||
import org.springframework.binding.convert.ConversionContext;
|
||||
import org.springframework.binding.expression.Expression;
|
||||
import org.springframework.binding.expression.ExpressionParser;
|
||||
import org.springframework.binding.expression.SettableExpression;
|
||||
import org.springframework.binding.expression.support.StaticExpression;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Converter that converts a String into an Expression object.
|
||||
*
|
||||
* @see org.springframework.binding.expression.Expression
|
||||
* @see org.springframework.binding.expression.SettableExpression
|
||||
*
|
||||
* @author Erwin Vervaet
|
||||
*/
|
||||
public class TextToExpression extends AbstractConverter {
|
||||
|
||||
/**
|
||||
* The expression string parser.
|
||||
*/
|
||||
private ExpressionParser expressionParser;
|
||||
|
||||
/**
|
||||
* Creates a new string-to-expression converter.
|
||||
* @param expressionParser the expression string parser
|
||||
*/
|
||||
public TextToExpression(ExpressionParser expressionParser) {
|
||||
Assert.notNull(expressionParser, "The expression parser is required");
|
||||
this.expressionParser = expressionParser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the expression parser used by this converter.
|
||||
*/
|
||||
public ExpressionParser getExpressionParser() {
|
||||
return expressionParser;
|
||||
}
|
||||
|
||||
public Class[] getSourceClasses() {
|
||||
return new Class[] { String.class };
|
||||
}
|
||||
|
||||
public Class[] getTargetClasses() {
|
||||
return new Class[] { Expression.class, SettableExpression.class };
|
||||
}
|
||||
|
||||
protected Object doConvert(Object source, Class targetClass, ConversionContext context) throws Exception {
|
||||
String expressionString = (String)source;
|
||||
if (getExpressionParser().isDelimitedExpression(expressionString)) {
|
||||
return getExpressionParser().parseExpression((String)source);
|
||||
}
|
||||
else {
|
||||
return new StaticExpression(expressionString);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.convert.support;
|
||||
|
||||
import org.springframework.binding.convert.ConversionContext;
|
||||
import org.springframework.binding.format.support.LabeledEnumFormatter;
|
||||
import org.springframework.core.enums.LabeledEnum;
|
||||
|
||||
/**
|
||||
* Converter that converts textual representations of enum
|
||||
* instances to a specific instance of <code>LabeledEnum</code>.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class TextToLabeledEnum extends AbstractConverter {
|
||||
|
||||
private LabeledEnumFormatter labeledEnumFormatter = new LabeledEnumFormatter();
|
||||
|
||||
public Class[] getSourceClasses() {
|
||||
return new Class[] { String.class };
|
||||
}
|
||||
|
||||
public Class[] getTargetClasses() {
|
||||
return new Class[] { LabeledEnum.class };
|
||||
}
|
||||
|
||||
protected Object doConvert(Object source, Class targetClass, ConversionContext context) throws Exception {
|
||||
return labeledEnumFormatter.parseValue((String)source, targetClass);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.convert.support;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.springframework.binding.convert.ConversionContext;
|
||||
import org.springframework.binding.format.FormatterFactory;
|
||||
import org.springframework.binding.format.support.SimpleFormatterFactory;
|
||||
|
||||
/**
|
||||
* Converts textual representations of numbers to a <code>Number</code>
|
||||
* specialization. Delegates to a synchronized formatter to parse text strings.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class TextToNumber extends AbstractFormattingConverter {
|
||||
|
||||
/**
|
||||
* Default constructor that uses a {@link SimpleFormatterFactory}.
|
||||
*/
|
||||
public TextToNumber() {
|
||||
super(new SimpleFormatterFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a string to number converter using given formatter factory.
|
||||
* @param formatterFactory the factory to use
|
||||
*/
|
||||
public TextToNumber(FormatterFactory formatterFactory) {
|
||||
super(formatterFactory);
|
||||
}
|
||||
|
||||
public Class[] getSourceClasses() {
|
||||
return new Class[] { String.class };
|
||||
}
|
||||
|
||||
public Class[] getTargetClasses() {
|
||||
return new Class[] { Integer.class, Short.class, Byte.class, Long.class, Float.class, Double.class,
|
||||
BigInteger.class, BigDecimal.class };
|
||||
}
|
||||
|
||||
protected Object doConvert(Object source, Class targetClass, ConversionContext context) throws Exception {
|
||||
return getFormatterFactory().getNumberFormatter(targetClass).parseValue((String)source, targetClass);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<html>
|
||||
<body>
|
||||
<p>
|
||||
Supporting type converter implementations that are generically applicable and frequently used.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.expression;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
|
||||
/**
|
||||
* A simple holder for information about an evaluation attempt.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class EvaluationAttempt implements Serializable {
|
||||
|
||||
/**
|
||||
* The expression that attempted to evaluate.
|
||||
*/
|
||||
private Expression expression;
|
||||
|
||||
/**
|
||||
* The target object being evaluated.
|
||||
*/
|
||||
private Object target;
|
||||
|
||||
/**
|
||||
* The evaluation context.
|
||||
*/
|
||||
private EvaluationContext context;
|
||||
|
||||
/**
|
||||
* Create an evaluation attempt.
|
||||
* @param expression the expression that failed to evaluate
|
||||
* @param target the target of the expression
|
||||
* @param context the context attributes that might have affected evaluation behavior
|
||||
*/
|
||||
public EvaluationAttempt(Expression expression, Object target, EvaluationContext context) {
|
||||
this.expression = expression;
|
||||
this.target = target;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the expression that attempted to evaluate.
|
||||
*/
|
||||
public Expression getExpression() {
|
||||
return expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the target object upon which evaluation was attempted.
|
||||
*/
|
||||
public Object getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns context attributes that may have influenced the evaluation process.
|
||||
*/
|
||||
public EvaluationContext getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return createToString(new ToStringCreator(this)).toString();
|
||||
}
|
||||
|
||||
protected ToStringCreator createToString(ToStringCreator creator) {
|
||||
return creator.append("expression", expression).append("target", target).append("context",
|
||||
context);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.expression;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A context object with two main responsibities:
|
||||
* <ol>
|
||||
* <li>Exposing information to an expression to influence
|
||||
* an evaluation attempt.
|
||||
* <li>Providing operations for recording progress or
|
||||
* errors during the expression evaluation process.
|
||||
* </ol>
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public interface EvaluationContext {
|
||||
|
||||
/**
|
||||
* Returns a map of attributes that can be used to influence expression evaluation.
|
||||
* @return the evaluation attributes
|
||||
*/
|
||||
public Map getAttributes();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.expression;
|
||||
|
||||
import org.springframework.core.NestedRuntimeException;
|
||||
|
||||
/**
|
||||
* Indicates an expression evaluation failed.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class EvaluationException extends NestedRuntimeException {
|
||||
|
||||
/**
|
||||
* The evaluation attempt that failed.
|
||||
*/
|
||||
private EvaluationAttempt evaluationAttempt;
|
||||
|
||||
/**
|
||||
* Creates a new evaluation exception.
|
||||
* @param evaluationAttempt the evaluation attempt that failed
|
||||
* @param cause the underlying cause of this exception
|
||||
*/
|
||||
public EvaluationException(EvaluationAttempt evaluationAttempt, Throwable cause) {
|
||||
super("Expression " + evaluationAttempt
|
||||
+ " failed - make sure the expression is evaluatable on the target object", cause);
|
||||
this.evaluationAttempt = evaluationAttempt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the evaluation attempt that failed.
|
||||
*/
|
||||
public EvaluationAttempt getEvaluationAttempt() {
|
||||
return evaluationAttempt;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.expression;
|
||||
|
||||
/**
|
||||
* Evaluates a single parsed expression on the provided input object in the
|
||||
* specified context. This provides a common abstraction for expression
|
||||
* evaluation independent of any language like OGNL or Spring's BeanWrapper.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public interface Expression {
|
||||
|
||||
/**
|
||||
* Evaluate the expression encapsulated by this evaluator against the
|
||||
* provided target object and return the result of the evaluation.
|
||||
* @param target the target of the expression
|
||||
* @param context the expression evaluation context
|
||||
* @return the evaluation result
|
||||
* @throws EvaluationException an exception occured during evaluation
|
||||
*/
|
||||
public Object evaluate(Object target, EvaluationContext context) throws EvaluationException;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.expression;
|
||||
|
||||
/**
|
||||
* Parses expression strings, returing a configured evaluator instance capable
|
||||
* of performing parsed expression evaluation in a thread safe way.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public interface ExpressionParser {
|
||||
|
||||
/**
|
||||
* Is this expression string delimited in a manner that indicates it is a
|
||||
* parseable expression? For example "${expression}".
|
||||
* @param expressionString the proposed expression string
|
||||
* @return true if yes, false if not
|
||||
*/
|
||||
public boolean isDelimitedExpression(String expressionString);
|
||||
|
||||
/**
|
||||
* Parse the provided expression string, returning an evaluator capable of
|
||||
* evaluating it against input.
|
||||
* @param expressionString the parseable expression string
|
||||
* @return the evaluator for the parsed expression
|
||||
* @throws ParserException an exception occured during parsing
|
||||
*/
|
||||
public Expression parseExpression(String expressionString) throws ParserException;
|
||||
|
||||
/**
|
||||
* Parse the provided settable expression string, returning an evaluator
|
||||
* capable of evaluating its value as well as setting its value.
|
||||
* @param expressionString the parseable expression string
|
||||
* @return the evaluator for the parsed expression
|
||||
* @throws ParserException an exception occured during parsing
|
||||
* @throws UnsupportedOperationException this parser does not support
|
||||
* settable expressions
|
||||
*/
|
||||
public SettableExpression parseSettableExpression(String expressionString) throws ParserException,
|
||||
UnsupportedOperationException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.expression;
|
||||
|
||||
import org.springframework.core.NestedRuntimeException;
|
||||
|
||||
/**
|
||||
* Base class for exceptions thrown during expression parsing.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class ParserException extends NestedRuntimeException {
|
||||
|
||||
/**
|
||||
* The expression string that could not be parsed.
|
||||
*/
|
||||
private String expressionString;
|
||||
|
||||
/**
|
||||
* Creates a new expression parsing exception.
|
||||
* @param expressionString the expression string that could not be parsed
|
||||
* @param cause the underlying cause of this exception
|
||||
*/
|
||||
public ParserException(String expressionString, Throwable cause) {
|
||||
this(expressionString, "Unable to parse expression string '" + expressionString + "'", cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new expression parsing exception.
|
||||
* @param expressionString the expression string that could not be parsed
|
||||
* @param message a descriptive message
|
||||
* @param cause the underlying cause of this exception
|
||||
*/
|
||||
public ParserException(String expressionString, String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
this.expressionString = expressionString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the expression string that could not be parsed.
|
||||
*/
|
||||
public Object getExpressionString() {
|
||||
return expressionString;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.expression;
|
||||
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
|
||||
/**
|
||||
* Records an attempt to set an expression value.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class SetValueAttempt extends EvaluationAttempt {
|
||||
|
||||
/**
|
||||
* The new value.
|
||||
*/
|
||||
private Object value;
|
||||
|
||||
/**
|
||||
* Creates a new set attempt.
|
||||
* @param expression the settable expression
|
||||
* @param target the target of the expression
|
||||
* @param value the value that was attempted to be set
|
||||
* @param context context attributes that may have influenced the evaluation and set process
|
||||
*/
|
||||
public SetValueAttempt(SettableExpression expression, Object target, Object value, EvaluationContext context) {
|
||||
super(expression, target, context);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value that was attempted to be set.
|
||||
*/
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
protected ToStringCreator createToString(ToStringCreator creator) {
|
||||
return super.createToString(creator).append("value", value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.expression;
|
||||
|
||||
/**
|
||||
* An evaluator that is capable of setting a value on a target object at the
|
||||
* path defined by this expression.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public interface SettableExpression extends Expression {
|
||||
|
||||
/**
|
||||
* Evaluate this expression against the target object to set its value to
|
||||
* the value provided.
|
||||
* @param target the target object
|
||||
* @param value the new value to be set
|
||||
* @param context the evaluation context
|
||||
* @throws EvaluationException an exception occured during evaluation
|
||||
*/
|
||||
public void evaluateToSet(Object target, Object value, EvaluationContext context) throws EvaluationException;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<html>
|
||||
<body>
|
||||
<p>
|
||||
Core expression language abstraction for parsing and evaluating expressions.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.expression.support;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.binding.expression.Expression;
|
||||
import org.springframework.binding.expression.ExpressionParser;
|
||||
import org.springframework.binding.expression.ParserException;
|
||||
import org.springframework.binding.expression.SettableExpression;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Abstract base class for expression parsers.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public abstract class AbstractExpressionParser implements ExpressionParser {
|
||||
|
||||
/**
|
||||
* The expression prefix.
|
||||
*/
|
||||
private static final String DEFAULT_EXPRESSION_PREFIX = "${";
|
||||
|
||||
/**
|
||||
* The expression suffix.
|
||||
*/
|
||||
private static final String DEFAULT_EXPRESSION_SUFFIX = "}";
|
||||
|
||||
/**
|
||||
* The marked expression delimter prefix.
|
||||
*/
|
||||
private String expressionPrefix = DEFAULT_EXPRESSION_PREFIX;
|
||||
|
||||
/**
|
||||
* The marked expression delimiter suffix.
|
||||
*/
|
||||
private String expressionSuffix = DEFAULT_EXPRESSION_SUFFIX;
|
||||
|
||||
/**
|
||||
* Returns the configured expression delimiter prefix. Defaults to "${".
|
||||
*/
|
||||
public String getExpressionPrefix() {
|
||||
return expressionPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the expression delimiter prefix.
|
||||
*/
|
||||
public void setExpressionPrefix(String expressionPrefix) {
|
||||
this.expressionPrefix = expressionPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the expression delimiter suffix. Defaults to "}".
|
||||
*/
|
||||
public String getExpressionSuffix() {
|
||||
return expressionSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the expression delimiter suffix.
|
||||
*/
|
||||
public void setExpressionSuffix(String expressionSuffix) {
|
||||
this.expressionSuffix = expressionSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether or not given criteria are expressed as an expression.
|
||||
*/
|
||||
public boolean isDelimitedExpression(String expressionString) {
|
||||
int prefixIndex = expressionString.indexOf(getExpressionPrefix());
|
||||
if (prefixIndex == -1) {
|
||||
return false;
|
||||
}
|
||||
int suffixIndex = expressionString.indexOf(getExpressionSuffix(), prefixIndex);
|
||||
if (suffixIndex == -1) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
if (suffixIndex == prefixIndex + getExpressionPrefix().length()) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final Expression parseExpression(String expressionString) throws ParserException {
|
||||
Expression[] expressions = parseExpressions(expressionString);
|
||||
if (expressions.length == 1) {
|
||||
return expressions[0];
|
||||
}
|
||||
else {
|
||||
return new CompositeStringExpression(expressions);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract SettableExpression parseSettableExpression(String expressionString) throws ParserException,
|
||||
UnsupportedOperationException;
|
||||
|
||||
/**
|
||||
* Helper that parses given expression string using the configured parser.
|
||||
* The expression string can contain any number of expressions all contained
|
||||
* in "${...}" markers. For instance: "foo${expr0}bar${expr1}". The static
|
||||
* pieces of text will also be returned as Expressions that just return that
|
||||
* static piece of text. As a result, evaluating all returned expressions
|
||||
* and concating the results produces the complete evaluated string.
|
||||
* @param expressionString the expression string
|
||||
* @return the parsed expressions
|
||||
* @throws ParserException when the expressions cannot be parsed
|
||||
*/
|
||||
private Expression[] parseExpressions(String expressionString) throws ParserException {
|
||||
List expressions = new LinkedList();
|
||||
if (StringUtils.hasText(expressionString)) {
|
||||
int startIdx = 0;
|
||||
while (startIdx < expressionString.length()) {
|
||||
int prefixIndex = expressionString.indexOf(getExpressionPrefix(), startIdx);
|
||||
if (prefixIndex >= startIdx) {
|
||||
// an expression was found
|
||||
if (prefixIndex > startIdx) {
|
||||
expressions.add(new StaticExpression(expressionString.substring(startIdx, prefixIndex)));
|
||||
startIdx = prefixIndex;
|
||||
}
|
||||
int suffixIndex = expressionString.indexOf(getExpressionSuffix(), prefixIndex);
|
||||
if (suffixIndex == -1) {
|
||||
throw new ParserException(expressionString, "No ending suffix '" + getExpressionSuffix()
|
||||
+ "' for expression starting at character " + prefixIndex + ": "
|
||||
+ expressionString.substring(prefixIndex), null);
|
||||
}
|
||||
else if (suffixIndex == prefixIndex + getExpressionPrefix().length()) {
|
||||
throw new ParserException(expressionString, "No expression defined within delimiter '"
|
||||
+ getExpressionPrefix() + getExpressionSuffix() + "' at character " + prefixIndex,
|
||||
null);
|
||||
}
|
||||
else {
|
||||
String expr = expressionString.substring(prefixIndex + getExpressionPrefix().length(),
|
||||
suffixIndex);
|
||||
expressions.add(doParseExpression(expr));
|
||||
startIdx = suffixIndex + 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (startIdx == 0) {
|
||||
// treat entire string as one expression
|
||||
expressions.add(doParseExpression(expressionString));
|
||||
}
|
||||
else {
|
||||
// no more ${expressions} found in string
|
||||
expressions.add(new StaticExpression(expressionString.substring(startIdx)));
|
||||
}
|
||||
startIdx = expressionString.length();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
expressions.add(new StaticExpression(expressionString));
|
||||
}
|
||||
return (Expression[]) expressions.toArray(new Expression[expressions.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method for parsing a filtered expression string. Subclasses should
|
||||
* override.
|
||||
* @param expressionString the expression string
|
||||
* @return the parsed expression
|
||||
*/
|
||||
protected abstract Expression doParseExpression(String expressionString);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.expression.support;
|
||||
|
||||
import org.springframework.beans.BeanWrapperImpl;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.binding.expression.EvaluationAttempt;
|
||||
import org.springframework.binding.expression.EvaluationContext;
|
||||
import org.springframework.binding.expression.EvaluationException;
|
||||
import org.springframework.binding.expression.SetValueAttempt;
|
||||
import org.springframework.binding.expression.SettableExpression;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* An expression evaluator that uses the Spring bean wrapper.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
class BeanWrapperExpression implements SettableExpression {
|
||||
|
||||
/**
|
||||
* The expression.
|
||||
*/
|
||||
private String expression;
|
||||
|
||||
public BeanWrapperExpression(String expression) {
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return expression.hashCode();
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof BeanWrapperExpression)) {
|
||||
return false;
|
||||
}
|
||||
BeanWrapperExpression other = (BeanWrapperExpression)o;
|
||||
return expression.equals(other.expression);
|
||||
}
|
||||
|
||||
public Object evaluate(Object target, EvaluationContext context) throws EvaluationException {
|
||||
try {
|
||||
return new BeanWrapperImpl(target).getPropertyValue(expression);
|
||||
}
|
||||
catch (BeansException e) {
|
||||
throw new EvaluationException(new EvaluationAttempt(this, target, context), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void evaluateToSet(Object target, Object value, EvaluationContext context) throws EvaluationException {
|
||||
try {
|
||||
Assert.notNull(target, "The target object to evaluate is required");
|
||||
new BeanWrapperImpl(target).setPropertyValue(expression, value);
|
||||
}
|
||||
catch (BeansException e) {
|
||||
throw new EvaluationException(new SetValueAttempt(this, target, value, context), e);
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return expression;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.expression.support;
|
||||
|
||||
import org.springframework.binding.expression.Expression;
|
||||
import org.springframework.binding.expression.ParserException;
|
||||
import org.springframework.binding.expression.SettableExpression;
|
||||
|
||||
/**
|
||||
* An expression parser that parses bean wrapper expressions.
|
||||
*
|
||||
* @author Keith
|
||||
*/
|
||||
public class BeanWrapperExpressionParser extends AbstractExpressionParser {
|
||||
|
||||
protected Expression doParseExpression(String expressionString) throws ParserException {
|
||||
return parseSettableExpression(expressionString);
|
||||
}
|
||||
|
||||
public SettableExpression parseSettableExpression(String expressionString) throws ParserException {
|
||||
return new BeanWrapperExpression(expressionString);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.expression.support;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.binding.expression.EvaluationContext;
|
||||
import org.springframework.binding.expression.EvaluationException;
|
||||
import org.springframework.binding.expression.Expression;
|
||||
import org.springframework.binding.expression.SetValueAttempt;
|
||||
import org.springframework.binding.expression.SettableExpression;
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A settable expression that adds non-null values to a collection.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class CollectionAddingExpression implements SettableExpression {
|
||||
|
||||
/**
|
||||
* The expression that resolves a mutable collection reference.
|
||||
*/
|
||||
private Expression collectionExpression;
|
||||
|
||||
/**
|
||||
* Creates a collection adding property expression.
|
||||
* @param collectionExpression the collection expression
|
||||
*/
|
||||
public CollectionAddingExpression(Expression collectionExpression) {
|
||||
this.collectionExpression = collectionExpression;
|
||||
}
|
||||
|
||||
public Object evaluate(Object target, EvaluationContext context) throws EvaluationException {
|
||||
return collectionExpression.evaluate(target, context);
|
||||
}
|
||||
|
||||
public void evaluateToSet(Object target, Object value, EvaluationContext context) throws EvaluationException {
|
||||
Object result = evaluate(target, context);
|
||||
if (result == null) {
|
||||
throw new EvaluationException(new SetValueAttempt(this, target, value, null),
|
||||
new IllegalArgumentException("The collection expression evaluated to a [null] reference"));
|
||||
}
|
||||
Assert.isInstanceOf(Collection.class, result, "Not a collection: ");
|
||||
if (value != null) {
|
||||
// add the value to the collection
|
||||
((Collection)result).add(value);
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return new ToStringCreator(this).append("collectionExpression", collectionExpression).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.expression.support;
|
||||
|
||||
import org.springframework.binding.expression.EvaluationContext;
|
||||
import org.springframework.binding.expression.EvaluationException;
|
||||
import org.springframework.binding.expression.Expression;
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
|
||||
/**
|
||||
* Evaluates an array of expressions to build a concatenated string.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class CompositeStringExpression implements Expression {
|
||||
|
||||
/**
|
||||
* The expression array.
|
||||
*/
|
||||
private Expression[] expressions;
|
||||
|
||||
/**
|
||||
* Creates a new composite string expression.
|
||||
* @param expressions the ordered set of expressions that when evaluated
|
||||
* will have their results stringed together to build the composite string
|
||||
*/
|
||||
public CompositeStringExpression(Expression[] expressions) {
|
||||
this.expressions = expressions;
|
||||
}
|
||||
|
||||
public Object evaluate(Object target, EvaluationContext evaluationContext) throws EvaluationException {
|
||||
StringBuffer buffer = new StringBuffer(128);
|
||||
for (int i = 0; i < expressions.length; i++) {
|
||||
buffer.append(expressions[i].evaluate(target, evaluationContext));
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return new ToStringCreator(this).append("expressions", expressions).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.expression.support;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import ognl.Ognl;
|
||||
import ognl.OgnlException;
|
||||
|
||||
import org.springframework.binding.expression.EvaluationAttempt;
|
||||
import org.springframework.binding.expression.EvaluationContext;
|
||||
import org.springframework.binding.expression.EvaluationException;
|
||||
import org.springframework.binding.expression.SetValueAttempt;
|
||||
import org.springframework.binding.expression.SettableExpression;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Evaluates a parsed Ognl expression.
|
||||
* <p>
|
||||
* IMPLEMENTATION NOTE: Ognl 2.6.7 expression objects do not respect equality
|
||||
* properly, so the equality operations defined within this class do not
|
||||
* function properly.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
class OgnlExpression implements SettableExpression {
|
||||
|
||||
/**
|
||||
* The expression.
|
||||
*/
|
||||
private Object expression;
|
||||
|
||||
/**
|
||||
* Creates a new OGNL expression.
|
||||
* @param expression the parsed expression
|
||||
*/
|
||||
public OgnlExpression(Object expression) {
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return expression.hashCode();
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof OgnlExpression)) {
|
||||
return false;
|
||||
}
|
||||
// as late as Ognl 2.6.7, their expression objects don't implement
|
||||
// equals
|
||||
// so this always returns false
|
||||
OgnlExpression other = (OgnlExpression) o;
|
||||
return expression.equals(other.expression);
|
||||
}
|
||||
|
||||
public Object evaluate(Object target, EvaluationContext context) throws EvaluationException {
|
||||
Assert.notNull(target, "The target object to evaluate is required");
|
||||
Map contextAttributes = (context != null ? context.getAttributes() : Collections.EMPTY_MAP);
|
||||
try {
|
||||
return Ognl.getValue(expression, contextAttributes, target);
|
||||
}
|
||||
catch (OgnlException e) {
|
||||
throw new EvaluationException(new EvaluationAttempt(this, target, context), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void evaluateToSet(Object target, Object value, EvaluationContext context) {
|
||||
Assert.notNull(target, "The target object to evaluate is required");
|
||||
Map contextAttributes = (context != null ? context.getAttributes() : Collections.EMPTY_MAP);
|
||||
try {
|
||||
Ognl.setValue(expression, contextAttributes, target, value);
|
||||
}
|
||||
catch (OgnlException e) {
|
||||
throw new EvaluationException(new SetValueAttempt(this, target, value, context), e);
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return expression.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.expression.support;
|
||||
|
||||
import ognl.Ognl;
|
||||
import ognl.OgnlException;
|
||||
import ognl.OgnlRuntime;
|
||||
import ognl.PropertyAccessor;
|
||||
|
||||
import org.springframework.binding.expression.Expression;
|
||||
import org.springframework.binding.expression.ParserException;
|
||||
import org.springframework.binding.expression.SettableExpression;
|
||||
|
||||
/**
|
||||
* An expression parser that parses Ognl expressions.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class OgnlExpressionParser extends AbstractExpressionParser {
|
||||
|
||||
protected Expression doParseExpression(String expressionString) throws ParserException {
|
||||
return parseSettableExpression(expressionString);
|
||||
}
|
||||
|
||||
public SettableExpression parseSettableExpression(String expressionString) throws ParserException {
|
||||
try {
|
||||
return new OgnlExpression(Ognl.parseExpression(expressionString));
|
||||
}
|
||||
catch (OgnlException e) {
|
||||
throw new ParserException(expressionString, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a property access strategy for the given class.
|
||||
* @param clazz the class that contains properties needing access
|
||||
* @param propertyAccessor the property access strategy
|
||||
*/
|
||||
public void addPropertyAccessor(Class clazz, PropertyAccessor propertyAccessor) {
|
||||
OgnlRuntime.setPropertyAccessor(clazz, propertyAccessor);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.expression.support;
|
||||
|
||||
import org.springframework.binding.expression.EvaluationContext;
|
||||
import org.springframework.binding.expression.EvaluationException;
|
||||
import org.springframework.binding.expression.Expression;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* A simple expression evaluator that just returns a fixed result on each
|
||||
* evaluation.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class StaticExpression implements Expression {
|
||||
|
||||
/**
|
||||
* The value expression.
|
||||
*/
|
||||
private Object value;
|
||||
|
||||
/**
|
||||
* Create a static evaluator for the given value.
|
||||
* @param value the value
|
||||
*/
|
||||
public StaticExpression(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
if (value == null) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return value.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof StaticExpression)) {
|
||||
return false;
|
||||
}
|
||||
StaticExpression other = (StaticExpression)o;
|
||||
return ObjectUtils.nullSafeEquals(value, other.value);
|
||||
}
|
||||
|
||||
public Object evaluate(Object target, EvaluationContext context) throws EvaluationException {
|
||||
return value;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return String.valueOf(value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<html>
|
||||
<body>
|
||||
<p>
|
||||
Expression abstraction implementations, integrated with BeanWrapper and OGNL.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.format;
|
||||
|
||||
/**
|
||||
* A lightweight interface for formatting a value and parsing a value from its
|
||||
* formatted form.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public interface Formatter {
|
||||
|
||||
/**
|
||||
* Format the value.
|
||||
* @param value the value to format
|
||||
* @return the formatted string, fit for display in a UI
|
||||
* @throws IllegalArgumentException the value could not be formatted
|
||||
*/
|
||||
public String formatValue(Object value) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Parse the formatted string representation of a value, restoring the
|
||||
* value.
|
||||
* @param formattedString the formatted string representation
|
||||
* @param targetClass the target class to convert the formatted value to
|
||||
* @return the parsed value
|
||||
* @throws InvalidFormatException the string was in an invalid form
|
||||
*/
|
||||
public Object parseValue(String formattedString, Class targetClass) throws InvalidFormatException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.format;
|
||||
|
||||
import java.text.Format;
|
||||
|
||||
/**
|
||||
* Source for shared and commonly used <code>Formatters</code>.
|
||||
* <p>
|
||||
* Formatters are typically not thread safe as <code>Format</code> objects
|
||||
* aren't thread safe: so implementations of this service should take care to
|
||||
* synchronize them as neccessary.
|
||||
*
|
||||
* @see Format
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public interface FormatterFactory {
|
||||
|
||||
/**
|
||||
* Returns a date formatter for the encoded date format.
|
||||
* @param encodedFormat the format
|
||||
* @return the formatter
|
||||
*/
|
||||
public Formatter getDateFormatter(String encodedFormat);
|
||||
|
||||
/**
|
||||
* Returns the default date format for the current locale.
|
||||
* @return the date formatter
|
||||
*/
|
||||
public Formatter getDateFormatter();
|
||||
|
||||
/**
|
||||
* Returns the date format with the specified style for the current locale.
|
||||
* @param style the style
|
||||
* @return the formatter
|
||||
*/
|
||||
public Formatter getDateFormatter(Style style);
|
||||
|
||||
/**
|
||||
* Returns the default date/time format for the current locale.
|
||||
* @return the date/time formatter
|
||||
*/
|
||||
public Formatter getDateTimeFormatter();
|
||||
|
||||
/**
|
||||
* Returns the date format with the specified styles for the current locale.
|
||||
* @param dateStyle the date style
|
||||
* @param timeStyle the time style
|
||||
* @return the formatter
|
||||
*/
|
||||
public Formatter getDateTimeFormatter(Style dateStyle, Style timeStyle);
|
||||
|
||||
/**
|
||||
* Returns the default time format for the current locale.
|
||||
* @return the time formatter
|
||||
*/
|
||||
public Formatter getTimeFormatter();
|
||||
|
||||
/**
|
||||
* Returns the time format with the specified style for the current locale.
|
||||
* @param style the style
|
||||
* @return the formatter
|
||||
*/
|
||||
public Formatter getTimeFormatter(Style style);
|
||||
|
||||
/**
|
||||
* Returns a number formatter for the specified class.
|
||||
* @param numberClass the number class
|
||||
* @return the number formatter
|
||||
*/
|
||||
public Formatter getNumberFormatter(Class numberClass);
|
||||
|
||||
/**
|
||||
* Returns a percent number formatter.
|
||||
* @return the percent formatter
|
||||
*/
|
||||
public Formatter getPercentFormatter();
|
||||
|
||||
/**
|
||||
* Returns a currency number formatter.
|
||||
* @return the currency formatter
|
||||
*/
|
||||
public Formatter getCurrencyFormatter();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.format;
|
||||
|
||||
import org.springframework.core.NestedRuntimeException;
|
||||
|
||||
/**
|
||||
* Thrown when a formatted value is of the wrong form.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class InvalidFormatException extends NestedRuntimeException {
|
||||
|
||||
private String invalidValue;
|
||||
|
||||
private String expectedFormat;
|
||||
|
||||
/**
|
||||
* Create a new invalid format exception
|
||||
* @param invalidValue the invalid value
|
||||
* @param expectedFormat the expected format
|
||||
*/
|
||||
public InvalidFormatException(String invalidValue, String expectedFormat) {
|
||||
this(invalidValue, expectedFormat, (Throwable)null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new invalid format exception
|
||||
* @param invalidValue the invalid value
|
||||
* @param expectedFormat the expected format
|
||||
* @param cause the underlying cause of this exception
|
||||
*/
|
||||
public InvalidFormatException(String invalidValue, String expectedFormat, Throwable cause) {
|
||||
super("Invalid format for value " + invalidValue + "; the expected format was '" + expectedFormat + "'", cause);
|
||||
this.invalidValue = invalidValue;
|
||||
this.expectedFormat = expectedFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new invalid format exception
|
||||
* @param invalidValue the invalid value
|
||||
* @param expectedFormat the expected format
|
||||
* @param message a descriptive message
|
||||
* @param cause the underlying cause of this exception
|
||||
*/
|
||||
public InvalidFormatException(String invalidValue, String expectedFormat, String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
this.invalidValue = invalidValue;
|
||||
this.expectedFormat = expectedFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the invalid value.
|
||||
*/
|
||||
public String getInvalidValue() {
|
||||
return invalidValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the expected format.
|
||||
*/
|
||||
public String getExpectedFormat() {
|
||||
return expectedFormat;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.format;
|
||||
|
||||
import org.springframework.core.enums.StaticLabeledEnum;
|
||||
|
||||
/**
|
||||
* Format styles.
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class Style extends StaticLabeledEnum {
|
||||
|
||||
public static final Style FULL = new Style(0, "Full");
|
||||
|
||||
public static final Style LONG = new Style(1, "Long");
|
||||
|
||||
public static final Style MEDIUM = new Style(2, "Medium");
|
||||
|
||||
public static final Style SHORT = new Style(3, "Short");
|
||||
|
||||
/**
|
||||
* Private constructor since this is a type-safe enum.
|
||||
*/
|
||||
private Style(int code, String label) {
|
||||
super(code, label);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<html>
|
||||
<body>
|
||||
<p>
|
||||
Core services for formatting objects in string form.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.format.support;
|
||||
|
||||
import java.text.ParseException;
|
||||
|
||||
import org.springframework.binding.format.Formatter;
|
||||
import org.springframework.binding.format.InvalidFormatException;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Abstract base class for all formatters.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public abstract class AbstractFormatter implements Formatter {
|
||||
|
||||
/**
|
||||
* Does this formatter allow empty values?
|
||||
*/
|
||||
private boolean allowEmpty = true;
|
||||
|
||||
/**
|
||||
* Constructs a formatter.
|
||||
*/
|
||||
protected AbstractFormatter() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a formatter.
|
||||
* @param allowEmpty allow formatting of empty (null or blank) values?
|
||||
*/
|
||||
protected AbstractFormatter(boolean allowEmpty) {
|
||||
this.allowEmpty = allowEmpty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow formatting of empty (null or blank) values?
|
||||
*/
|
||||
public boolean isAllowEmpty() {
|
||||
return allowEmpty;
|
||||
}
|
||||
|
||||
public final String formatValue(Object value) {
|
||||
if (allowEmpty && isEmpty(value)) {
|
||||
return getEmptyFormattedValue();
|
||||
}
|
||||
Assert.isTrue(!isEmpty(value), "Object to format cannot be empty");
|
||||
return doFormatValue(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method subclasses should override to encapsulate formatting
|
||||
* logic.
|
||||
* @param value the value to format
|
||||
* @return the formatted string representation
|
||||
*/
|
||||
protected abstract String doFormatValue(Object value);
|
||||
|
||||
/**
|
||||
* Returns the formatted form of an empty value. Default implementation
|
||||
* just returns the empty string.
|
||||
*/
|
||||
protected String getEmptyFormattedValue() {
|
||||
return "";
|
||||
}
|
||||
|
||||
public final Object parseValue(String formattedString, Class targetClass) throws InvalidFormatException {
|
||||
try {
|
||||
if (allowEmpty && isEmpty(formattedString)) {
|
||||
return getEmptyValue();
|
||||
}
|
||||
return doParseValue(formattedString, targetClass);
|
||||
}
|
||||
catch (ParseException ex) {
|
||||
throw new InvalidFormatException(formattedString, getExpectedFormat(targetClass), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method subclasses should override to encapsulate parsing logic.
|
||||
* @param formattedString the formatted string to parse
|
||||
* @return the parsed value
|
||||
* @throws InvalidFormatException an exception occured parsing
|
||||
* @throws ParseException when parse exceptions occur
|
||||
*/
|
||||
protected abstract Object doParseValue(String formattedString, Class targetClass) throws InvalidFormatException,
|
||||
ParseException;
|
||||
|
||||
/**
|
||||
* Returns the empty value (resulting from parsing an empty input string).
|
||||
* This default implementation just returns null.
|
||||
*/
|
||||
protected Object getEmptyValue() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the expected string format for the given target class.
|
||||
* The default implementation just returns null.
|
||||
*/
|
||||
protected String getExpectedFormat(Class targetClass) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is given object <i>empty</i> (null or empty string)?
|
||||
*/
|
||||
protected boolean isEmpty(Object o) {
|
||||
if (o == null) {
|
||||
return true;
|
||||
}
|
||||
else if (o instanceof String) {
|
||||
return !StringUtils.hasText((String)o);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.format.support;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.springframework.binding.format.Formatter;
|
||||
import org.springframework.binding.format.FormatterFactory;
|
||||
import org.springframework.binding.format.Style;
|
||||
import org.springframework.context.i18n.LocaleContext;
|
||||
import org.springframework.context.i18n.SimpleLocaleContext;
|
||||
|
||||
/**
|
||||
* Base class for formatter factories.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public abstract class AbstractFormatterFactory implements FormatterFactory {
|
||||
|
||||
private LocaleContext localeContext = new SimpleLocaleContext(Locale.getDefault());
|
||||
|
||||
private Style defaultDateStyle = Style.MEDIUM;
|
||||
|
||||
private Style defaultTimeStyle = Style.MEDIUM;
|
||||
|
||||
/**
|
||||
* Set's the locale context used. Defaults to a SimpleLocaleContext holding
|
||||
* the system default locale.
|
||||
*/
|
||||
public void setLocaleContext(LocaleContext localeContext) {
|
||||
this.localeContext = localeContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the locale in use.
|
||||
*/
|
||||
protected Locale getLocale() {
|
||||
return localeContext.getLocale();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default date style. Defaults to {@link Style#MEDIUM}.
|
||||
*/
|
||||
protected Style getDefaultDateStyle() {
|
||||
return defaultDateStyle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default date style.
|
||||
*/
|
||||
public void setDefaultDateStyle(Style defaultDateStyle) {
|
||||
this.defaultDateStyle = defaultDateStyle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default time style. Defaults to {@link Style#MEDIUM}.
|
||||
*/
|
||||
public Style getDefaultTimeStyle() {
|
||||
return defaultTimeStyle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default time style.
|
||||
*/
|
||||
public void setDefaultTimeStyle(Style defaultTimeStyle) {
|
||||
this.defaultTimeStyle = defaultTimeStyle;
|
||||
}
|
||||
|
||||
public Formatter getDateFormatter() {
|
||||
return getDateFormatter(getDefaultDateStyle());
|
||||
}
|
||||
|
||||
public Formatter getDateTimeFormatter() {
|
||||
return getDateTimeFormatter(getDefaultDateStyle(), getDefaultTimeStyle());
|
||||
}
|
||||
|
||||
public Formatter getTimeFormatter() {
|
||||
return getTimeFormatter(getDefaultTimeStyle());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.format.support;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.binding.format.InvalidFormatException;
|
||||
|
||||
/**
|
||||
* Formatter that formats date objects.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class DateFormatter extends AbstractFormatter {
|
||||
|
||||
private DateFormat dateFormat;
|
||||
|
||||
/**
|
||||
* Constructs a date formatter that will delegate to the specified date
|
||||
* format.
|
||||
* @param dateFormat the date format to use
|
||||
*/
|
||||
public DateFormatter(DateFormat dateFormat) {
|
||||
this.dateFormat = dateFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a date formatter that will delegate to the specified date
|
||||
* format.
|
||||
* @param dateFormat the date format to use
|
||||
* @param allowEmpty should this formatter allow empty input arguments?
|
||||
*/
|
||||
public DateFormatter(DateFormat dateFormat, boolean allowEmpty) {
|
||||
super(allowEmpty);
|
||||
this.dateFormat = dateFormat;
|
||||
}
|
||||
|
||||
// convert from date to string
|
||||
protected String doFormatValue(Object date) {
|
||||
return dateFormat.format((Date)date);
|
||||
}
|
||||
|
||||
// convert back from string to date
|
||||
protected Object doParseValue(String formattedString, Class targetClass) throws ParseException {
|
||||
return dateFormat.parse(formattedString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to parse a date.
|
||||
*/
|
||||
public Date parseDate(String formattedString) throws InvalidFormatException {
|
||||
return (Date)parseValue(formattedString, Date.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.format.support;
|
||||
|
||||
import java.beans.PropertyEditorSupport;
|
||||
|
||||
import org.springframework.binding.format.Formatter;
|
||||
|
||||
/**
|
||||
* Adapts a formatter to the property editor contract.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class FormatterPropertyEditor extends PropertyEditorSupport {
|
||||
|
||||
/**
|
||||
* The formatter
|
||||
*/
|
||||
private Formatter formatter;
|
||||
|
||||
/**
|
||||
* The target value class (may be null).
|
||||
*/
|
||||
private Class targetClass;
|
||||
|
||||
/**
|
||||
* Creates a formatter property editor.
|
||||
* @param formatter the formatter to adapt
|
||||
*/
|
||||
public FormatterPropertyEditor(Formatter formatter) {
|
||||
this.formatter = formatter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a formatter property editor.
|
||||
* @param formatter the formatter to adapt
|
||||
* @param targetClass the target class for "setAsText" conversions
|
||||
*/
|
||||
public FormatterPropertyEditor(Formatter formatter, Class targetClass) {
|
||||
this.formatter = formatter;
|
||||
this.targetClass = targetClass;
|
||||
}
|
||||
|
||||
public String getAsText() {
|
||||
return formatter.formatValue(getValue());
|
||||
}
|
||||
|
||||
public void setAsText(String text) throws IllegalArgumentException {
|
||||
setValue(formatter.parseValue(text, targetClass));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.format.support;
|
||||
|
||||
import org.springframework.binding.format.InvalidFormatException;
|
||||
import org.springframework.core.enums.LabeledEnum;
|
||||
import org.springframework.core.enums.LabeledEnumResolver;
|
||||
import org.springframework.core.enums.StaticLabeledEnumResolver;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Converts from string to a <cod>LabeledEnum</code> instance and back.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class LabeledEnumFormatter extends AbstractFormatter {
|
||||
|
||||
private LabeledEnumResolver labeledEnumResolver = StaticLabeledEnumResolver.instance();
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public LabeledEnumFormatter() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new LabeledEnum formatter.
|
||||
* @param allowEmpty should this formatter allow empty input arguments?
|
||||
*/
|
||||
public LabeledEnumFormatter(boolean allowEmpty) {
|
||||
super(allowEmpty);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the LabeledEnumResolver used. Defaults to {@link StaticLabeledEnumResolver}.
|
||||
*/
|
||||
public void setLabeledEnumResolver(LabeledEnumResolver labeledEnumResolver) {
|
||||
Assert.notNull(labeledEnumResolver, "The labeled enum resolver is required");
|
||||
this.labeledEnumResolver = labeledEnumResolver;
|
||||
}
|
||||
|
||||
protected String doFormatValue(Object value) {
|
||||
LabeledEnum labeledEnum = (LabeledEnum)value;
|
||||
return labeledEnum.getLabel();
|
||||
}
|
||||
|
||||
protected Object doParseValue(String formattedString, Class targetClass) throws IllegalArgumentException {
|
||||
LabeledEnum labeledEnum = labeledEnumResolver.getLabeledEnumByLabel(targetClass, formattedString);
|
||||
if (!isAllowEmpty()) {
|
||||
Assert.notNull(labeledEnum, "The label '" + formattedString
|
||||
+ "' did not map to a valid enum instance for type " + targetClass);
|
||||
Assert.isInstanceOf(targetClass, labeledEnum);
|
||||
}
|
||||
return labeledEnum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to parse a LabeledEnum.
|
||||
*/
|
||||
public LabeledEnum parseLabeledEnum(String formattedString, Class enumClass) throws InvalidFormatException {
|
||||
return (LabeledEnum)parseValue(formattedString, enumClass);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.format.support;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.text.NumberFormat;
|
||||
|
||||
import org.springframework.binding.format.InvalidFormatException;
|
||||
import org.springframework.util.NumberUtils;
|
||||
|
||||
/**
|
||||
* Converts from various
|
||||
* <code>Number<code> specializations to <code>String</code> and back.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class NumberFormatter extends AbstractFormatter {
|
||||
|
||||
private NumberFormat numberFormat;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public NumberFormatter() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new number formatter.
|
||||
* @param numberFormat the number format to use
|
||||
*/
|
||||
public NumberFormatter(NumberFormat numberFormat) {
|
||||
this.numberFormat = numberFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new number formatter.
|
||||
* @param numberFormat the number format to use
|
||||
* @param allowEmpty should this formatter allow empty input arguments?
|
||||
*/
|
||||
public NumberFormatter(NumberFormat numberFormat, boolean allowEmpty) {
|
||||
super(allowEmpty);
|
||||
this.numberFormat = numberFormat;
|
||||
}
|
||||
|
||||
protected String doFormatValue(Object number) {
|
||||
if (this.numberFormat != null) {
|
||||
// use NumberFormat for rendering value
|
||||
return this.numberFormat.format(number);
|
||||
}
|
||||
else {
|
||||
// use toString method for rendering value
|
||||
return number.toString();
|
||||
}
|
||||
}
|
||||
|
||||
protected Object doParseValue(String text, Class targetClass) throws IllegalArgumentException {
|
||||
// use given NumberFormat for parsing text
|
||||
if (this.numberFormat != null) {
|
||||
return NumberUtils.parseNumber(text, targetClass, this.numberFormat);
|
||||
}
|
||||
// use default valueOf methods for parsing text
|
||||
else {
|
||||
return NumberUtils.parseNumber(text, targetClass);
|
||||
}
|
||||
}
|
||||
|
||||
// convenience methods
|
||||
|
||||
public Short parseShort(String formattedString) throws InvalidFormatException {
|
||||
return (Short)parseValue(formattedString, Short.class);
|
||||
}
|
||||
|
||||
public Integer parseInteger(String formattedString) throws InvalidFormatException {
|
||||
return (Integer)parseValue(formattedString, Integer.class);
|
||||
}
|
||||
|
||||
public Long parseLong(String formattedString) throws InvalidFormatException {
|
||||
return (Long)parseValue(formattedString, Long.class);
|
||||
}
|
||||
|
||||
public Double parseDouble(String formattedString) throws InvalidFormatException {
|
||||
return (Double)parseValue(formattedString, Double.class);
|
||||
}
|
||||
|
||||
public Float parseFloat(String formattedString) throws InvalidFormatException {
|
||||
return (Float)parseValue(formattedString, Float.class);
|
||||
}
|
||||
|
||||
public BigInteger parseBigInteger(String formattedString) throws InvalidFormatException {
|
||||
return (BigInteger)parseValue(formattedString, BigInteger.class);
|
||||
}
|
||||
|
||||
public Byte parseByte(String formattedString) throws InvalidFormatException {
|
||||
return (Byte)parseValue(formattedString, Byte.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.format.support;
|
||||
|
||||
import java.beans.PropertyEditor;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Adapts a property editor to the formatter interface.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class PropertyEditorFormatter extends AbstractFormatter {
|
||||
|
||||
private PropertyEditor propertyEditor;
|
||||
|
||||
/**
|
||||
* Wrap given property editor in a formatter.
|
||||
*/
|
||||
public PropertyEditorFormatter(PropertyEditor propertyEditor) {
|
||||
Assert.notNull(propertyEditor, "Property editor is required");
|
||||
this.propertyEditor = propertyEditor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the wrapped property editor.
|
||||
*/
|
||||
public PropertyEditor getPropertyEditor() {
|
||||
return propertyEditor;
|
||||
}
|
||||
|
||||
protected String doFormatValue(Object value) {
|
||||
propertyEditor.setValue(value);
|
||||
return propertyEditor.getAsText();
|
||||
}
|
||||
|
||||
protected Object doParseValue(String formattedValue, Class targetClass) {
|
||||
propertyEditor.setAsText(formattedValue);
|
||||
return propertyEditor.getValue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.format.support;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
import org.springframework.binding.format.Formatter;
|
||||
import org.springframework.binding.format.Style;
|
||||
|
||||
/**
|
||||
* Simple FormatterFactory implementation.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class SimpleFormatterFactory extends AbstractFormatterFactory {
|
||||
|
||||
public SimpleFormatterFactory() {
|
||||
}
|
||||
|
||||
public Formatter getDateFormatter(Style style) {
|
||||
return new DateFormatter(SimpleDateFormat.getDateInstance(style.shortValue(), getLocale()));
|
||||
}
|
||||
|
||||
public Formatter getDateTimeFormatter(Style dateStyle, Style timeStyle) {
|
||||
return new DateFormatter(SimpleDateFormat.getDateTimeInstance(dateStyle.shortValue(), timeStyle.shortValue(),
|
||||
getLocale()));
|
||||
}
|
||||
|
||||
public Formatter getTimeFormatter(Style style) {
|
||||
return new DateFormatter(SimpleDateFormat.getTimeInstance(style.shortValue(), getLocale()));
|
||||
}
|
||||
|
||||
public Formatter getNumberFormatter(Class numberClass) {
|
||||
return new NumberFormatter(NumberFormat.getNumberInstance(getLocale()));
|
||||
}
|
||||
|
||||
public Formatter getCurrencyFormatter() {
|
||||
return new NumberFormatter(NumberFormat.getCurrencyInstance(getLocale()));
|
||||
}
|
||||
|
||||
public Formatter getDateFormatter(String encodedFormat) {
|
||||
return new DateFormatter(new SimpleDateFormat(encodedFormat));
|
||||
}
|
||||
|
||||
public Formatter getPercentFormatter() {
|
||||
return new NumberFormatter(NumberFormat.getPercentInstance(getLocale()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<html>
|
||||
<body>
|
||||
<p>
|
||||
Supporting formatter implementations that are generically applicable and frequently used.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.mapping;
|
||||
|
||||
/**
|
||||
* A lightweight service interface for mapping between two attribute sources.
|
||||
* <p>
|
||||
* Implementations of this interface are expected to encapsulate the mapping
|
||||
* configuration information as well as the logic to act on it to perform
|
||||
* mapping between a given source and target attribute source.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public interface AttributeMapper {
|
||||
|
||||
/**
|
||||
* Map data from a source object to a target object.
|
||||
* @param source the source
|
||||
* @param target the target
|
||||
* @param context the mapping context
|
||||
*/
|
||||
public void map(Object source, Object target, MappingContext context);
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.mapping;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
|
||||
/**
|
||||
* Generic attributes mapper implementation that allows mappings to be
|
||||
* configured programatically.
|
||||
*
|
||||
* @author Erwin Vervaet
|
||||
* @author Keith Donald
|
||||
* @author Colin Sampaleanu
|
||||
*/
|
||||
public class DefaultAttributeMapper implements AttributeMapper {
|
||||
|
||||
/**
|
||||
* The ordered list of mappings to apply.
|
||||
*/
|
||||
private List mappings = new LinkedList();
|
||||
|
||||
/**
|
||||
* Add a mapping to this mapper.
|
||||
* @param mapping the mapping to add (as an AttributeMapper)
|
||||
* @return this, to support convenient call chaining
|
||||
*/
|
||||
public DefaultAttributeMapper addMapping(AttributeMapper mapping) {
|
||||
mappings.add(mapping);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a set of mappings.
|
||||
* @param mappings the mappings
|
||||
*/
|
||||
public void addMappings(AttributeMapper[] mappings) {
|
||||
if (mappings == null) {
|
||||
return;
|
||||
}
|
||||
this.mappings.addAll(Arrays.asList(mappings));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this mapper's list of mappings.
|
||||
* @return the list of mappings
|
||||
*/
|
||||
public AttributeMapper[] getMappings() {
|
||||
return (AttributeMapper[])mappings.toArray(new AttributeMapper[mappings.size()]);
|
||||
}
|
||||
|
||||
public void map(Object source, Object target, MappingContext context) {
|
||||
if (mappings != null) {
|
||||
Iterator it = mappings.iterator();
|
||||
while (it.hasNext()) {
|
||||
AttributeMapper mapping = (AttributeMapper)it.next();
|
||||
mapping.map(source, target, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return new ToStringCreator(this).append("mappings", mappings).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.mapping;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.binding.convert.ConversionExecutor;
|
||||
import org.springframework.binding.expression.Expression;
|
||||
import org.springframework.binding.expression.SettableExpression;
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A single mapping definition, encapulating the information neccessary to map
|
||||
* the result of evaluating an expression on a source object to a property on a
|
||||
* target object, optionally applying a type conversion during the mapping
|
||||
* process.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class Mapping implements AttributeMapper {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(Mapping.class);
|
||||
|
||||
/**
|
||||
* The source expression to evaluate against a source object to map from.
|
||||
*/
|
||||
private final Expression sourceExpression;
|
||||
|
||||
/**
|
||||
* The target expression to set on a target object to map to.
|
||||
*/
|
||||
private final SettableExpression targetExpression;
|
||||
|
||||
/**
|
||||
* A type converter to apply during the mapping process.
|
||||
*/
|
||||
private final ConversionExecutor typeConverter;
|
||||
|
||||
/**
|
||||
* Whether or not this is a required mapping; if true, the source expression
|
||||
* must return a non-null value.
|
||||
*/
|
||||
private boolean required;
|
||||
|
||||
/**
|
||||
* Creates a new mapping.
|
||||
* @param sourceExpression the source expression
|
||||
* @param targetExpression the target expression
|
||||
* @param typeConverter a type converter
|
||||
*/
|
||||
public Mapping(Expression sourceExpression, SettableExpression targetExpression,
|
||||
ConversionExecutor typeConverter) {
|
||||
this(sourceExpression, targetExpression, typeConverter, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new mapping.
|
||||
* @param sourceExpression the source expression
|
||||
* @param targetExpression the target expression
|
||||
* @param typeConverter a type converter
|
||||
* @param required whether or not this mapping is required
|
||||
*/
|
||||
protected Mapping(Expression sourceExpression, SettableExpression targetExpression,
|
||||
ConversionExecutor typeConverter, boolean required) {
|
||||
Assert.notNull(sourceExpression, "The source expression is required");
|
||||
Assert.notNull(targetExpression, "The target expression is required");
|
||||
this.sourceExpression = sourceExpression;
|
||||
this.targetExpression = targetExpression;
|
||||
this.typeConverter = typeConverter;
|
||||
this.required = required;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map the <code>sourceAttribute</code> in to the
|
||||
* <code>targetAttribute</code> target map, performing type conversion if
|
||||
* necessary.
|
||||
* @param source The source data structure
|
||||
* @param target The target data structure
|
||||
*/
|
||||
public void map(Object source, Object target, MappingContext context) {
|
||||
// get source value
|
||||
Object sourceValue = sourceExpression.evaluate(source, null);
|
||||
if (sourceValue == null) {
|
||||
if (required) {
|
||||
throw new RequiredMappingException("This mapping is required; evaluation of expression '"
|
||||
+ sourceExpression + "' against source of type [" + source.getClass()
|
||||
+ "] must return a non-null value");
|
||||
}
|
||||
else {
|
||||
// source expression returned no value, simply abort mapping
|
||||
return;
|
||||
}
|
||||
}
|
||||
Object targetValue = sourceValue;
|
||||
if (typeConverter != null) {
|
||||
targetValue = typeConverter.execute(sourceValue);
|
||||
}
|
||||
// set target value
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Mapping '" + sourceExpression + "' value [" + sourceValue + "] to target property '"
|
||||
+ targetExpression + "'; setting property value to [" + targetValue + "]");
|
||||
}
|
||||
targetExpression.evaluateToSet(target, targetValue, null);
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof Mapping)) {
|
||||
return false;
|
||||
}
|
||||
Mapping other = (Mapping)o;
|
||||
return sourceExpression.equals(other.sourceExpression)
|
||||
&& targetExpression.equals(other.targetExpression);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return sourceExpression.hashCode() + targetExpression.hashCode();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return new ToStringCreator(this).append(sourceExpression + " -> " + targetExpression).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.mapping;
|
||||
|
||||
import org.springframework.binding.convert.ConversionExecutor;
|
||||
import org.springframework.binding.convert.ConversionService;
|
||||
import org.springframework.binding.convert.support.DefaultConversionService;
|
||||
import org.springframework.binding.expression.Expression;
|
||||
import org.springframework.binding.expression.ExpressionParser;
|
||||
import org.springframework.binding.expression.SettableExpression;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A stateful builder that builds {@link Mapping} objects. Designed for
|
||||
* convenience to build mappings in a clear, readable manner.
|
||||
* <p>
|
||||
* Example usage:
|
||||
*
|
||||
* <pre>
|
||||
* MappingBuilder mapping = new MappingBuilder();
|
||||
* Mapping result = mapping.source("foo").target("bar").from(String.class).to(Long.class).value();
|
||||
* </pre>
|
||||
*
|
||||
* Calling the {@link #value()} result method clears out this builder's state so
|
||||
* it can be reused to build another mapping.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class MappingBuilder {
|
||||
|
||||
/**
|
||||
* The expression string parser.
|
||||
*/
|
||||
private ExpressionParser expressionParser;
|
||||
|
||||
/**
|
||||
* The conversion service for applying type conversions.
|
||||
*/
|
||||
private ConversionService conversionService = new DefaultConversionService();
|
||||
|
||||
/**
|
||||
* The source mapping expression.
|
||||
*/
|
||||
private Expression sourceExpression;
|
||||
|
||||
/**
|
||||
* The target mapping settable expression.
|
||||
*/
|
||||
private SettableExpression targetExpression;
|
||||
|
||||
/**
|
||||
* The type of the object returned by evaluating the source expression.
|
||||
*/
|
||||
private Class sourceType;
|
||||
|
||||
/**
|
||||
* The type of the property settable by the target expression.
|
||||
*/
|
||||
private Class targetType;
|
||||
|
||||
/**
|
||||
* Whether or not the built mapping is a required mapping.
|
||||
*/
|
||||
private boolean required;
|
||||
|
||||
/**
|
||||
* Creates a mapping builder that uses the expression parser to parse
|
||||
* attribute mapping expressions.
|
||||
* @param expressionParser the expression parser
|
||||
*/
|
||||
public MappingBuilder(ExpressionParser expressionParser) {
|
||||
Assert.notNull(expressionParser, "The expression parser is required");
|
||||
this.expressionParser = expressionParser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the conversion service that will convert the object returned by
|
||||
* evaluating the source expression to the {@link #to(Class)} type if
|
||||
* necessary.
|
||||
* @param conversionService the conversion service
|
||||
*/
|
||||
public void setConversionService(ConversionService conversionService) {
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the source expression of the mapping built by this builder.
|
||||
* @param expressionString the expression string
|
||||
* @return this, to support call-chaining
|
||||
*/
|
||||
public MappingBuilder source(String expressionString) {
|
||||
sourceExpression = expressionParser.parseExpression(expressionString);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the target property expression of the mapping built by this builder.
|
||||
* @param expressionString the expression string
|
||||
* @return this, to support call-chaining
|
||||
*/
|
||||
public MappingBuilder target(String expressionString) {
|
||||
targetExpression = (SettableExpression)expressionParser.parseExpression(expressionString);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the expected type of the object returned by evaluating the source
|
||||
* expression. Used in conjunction with {@link #to(Class)} to perform a type
|
||||
* conversion during the mapping process.
|
||||
* @param sourceType the source type
|
||||
* @return this, to support call-chaining
|
||||
*/
|
||||
public MappingBuilder from(Class sourceType) {
|
||||
this.sourceType = sourceType;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the target type of the property writeable by the target expression.
|
||||
* @param targetType the target type
|
||||
* @return this, to support call-chaining
|
||||
*/
|
||||
public MappingBuilder to(Class targetType) {
|
||||
this.targetType = targetType;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the mapping to be built a "required" mapping.
|
||||
* @return this, to support call-chaining
|
||||
*/
|
||||
public MappingBuilder required() {
|
||||
this.required = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The logical GoF builder getResult method, returning a fully constructed
|
||||
* Mapping from the configured pieces. Once called, the state of this
|
||||
* builder is nulled out to support building a new mapping object again.
|
||||
* @return the mapping result
|
||||
*/
|
||||
public Mapping value() {
|
||||
Assert.notNull(sourceExpression, "The source expression must be set at a minimum");
|
||||
if (targetExpression == null) {
|
||||
targetExpression = (SettableExpression)sourceExpression;
|
||||
}
|
||||
ConversionExecutor typeConverter = null;
|
||||
if (sourceType != null) {
|
||||
Assert.notNull(targetType, "The target type is required when the source type is specified");
|
||||
typeConverter = conversionService.getConversionExecutor(sourceType, targetType);
|
||||
}
|
||||
Mapping result;
|
||||
if (required) {
|
||||
result = new RequiredMapping(sourceExpression, targetExpression, typeConverter);
|
||||
}
|
||||
else {
|
||||
result = new Mapping(sourceExpression, targetExpression, typeConverter);
|
||||
}
|
||||
reset();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset this mapping builder.
|
||||
*/
|
||||
public void reset() {
|
||||
sourceExpression = null;
|
||||
targetExpression = null;
|
||||
sourceType = null;
|
||||
targetType = null;
|
||||
required = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.mapping;
|
||||
|
||||
/**
|
||||
* A context object with two main responsibities:
|
||||
* <ol>
|
||||
* <li>Exposing information to a mapper to influence
|
||||
* a mapping attempt.
|
||||
* <li>Providing operations for recording progress or
|
||||
* errors during the mapping process.
|
||||
* </ol>
|
||||
* Empty for now; subclasses may define their own custom context behavior
|
||||
* accessible by a mapper with a downcast.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public interface MappingContext {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.mapping;
|
||||
|
||||
import org.springframework.binding.convert.ConversionExecutor;
|
||||
import org.springframework.binding.expression.Expression;
|
||||
import org.springframework.binding.expression.SettableExpression;
|
||||
|
||||
/**
|
||||
* A mapping that is required.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class RequiredMapping extends Mapping {
|
||||
|
||||
/**
|
||||
* Creates a required mapping.
|
||||
* @param sourceExpression the source mapping expression
|
||||
* @param targetPropertyExpression the target property expression
|
||||
* @param typeConverter a type converter
|
||||
*/
|
||||
public RequiredMapping(Expression sourceExpression, SettableExpression targetPropertyExpression,
|
||||
ConversionExecutor typeConverter) {
|
||||
super(sourceExpression, targetPropertyExpression, typeConverter, true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.mapping;
|
||||
|
||||
/**
|
||||
* Thrown when a required mapping could not be performed.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class RequiredMappingException extends IllegalStateException {
|
||||
|
||||
/**
|
||||
* Create a new required mapping exception.
|
||||
* @param message a descriptive message
|
||||
*/
|
||||
public RequiredMappingException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<html>
|
||||
<body>
|
||||
<p>
|
||||
Support for mapping attribute values between data structures.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.method;
|
||||
|
||||
import org.springframework.core.NestedRuntimeException;
|
||||
|
||||
/**
|
||||
* Thrown when a method key could not be resolved to an invokable java Method on
|
||||
* a Class.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class InvalidMethodKeyException extends NestedRuntimeException {
|
||||
|
||||
/**
|
||||
* The method key that could not be resolved.
|
||||
*/
|
||||
private MethodKey methodKey;
|
||||
|
||||
/**
|
||||
* Creates an exception signaling an invalid method signature.
|
||||
* @param methodKey the class method key
|
||||
* @param cause the cause
|
||||
*/
|
||||
public InvalidMethodKeyException(MethodKey methodKey, Exception cause) {
|
||||
super("Could not resolve method with key " + methodKey, cause);
|
||||
this.methodKey = methodKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the invalid method key.
|
||||
* @return the method key.
|
||||
*/
|
||||
public MethodKey getMethodKey() {
|
||||
return methodKey;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.method;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
import org.springframework.core.NestedRuntimeException;
|
||||
import org.springframework.core.style.StylerUtils;
|
||||
|
||||
/**
|
||||
* Base class for exceptions that report a method invocation failure.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class MethodInvocationException extends NestedRuntimeException {
|
||||
|
||||
/**
|
||||
* The method signature.
|
||||
*/
|
||||
private MethodSignature methodSignature;
|
||||
|
||||
/**
|
||||
* The method invocation argument values.
|
||||
*/
|
||||
private Object[] arguments;
|
||||
|
||||
/**
|
||||
* Signals that the method with the specified signature could not be invoked
|
||||
* with the provided arguments.
|
||||
* @param methodSignature the method signature
|
||||
* @param arguments the arguments
|
||||
* @param cause the root cause
|
||||
*/
|
||||
public MethodInvocationException(MethodSignature methodSignature, Object[] arguments, Exception cause) {
|
||||
super("Unable to invoke method " + methodSignature + " with arguments " + StylerUtils.style(arguments), cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the invoked method's signature.
|
||||
*/
|
||||
public MethodSignature getMethodSignature() {
|
||||
return methodSignature;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the method invocation arguments.
|
||||
*/
|
||||
public Object[] getArguments() {
|
||||
return arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the target root cause exception of the method invocation failure.
|
||||
* @return the target throwable
|
||||
*/
|
||||
public Throwable getTargetException() {
|
||||
if (getCause() instanceof InvocationTargetException) {
|
||||
return ((InvocationTargetException)getCause()).getTargetException();
|
||||
}
|
||||
else {
|
||||
return getCause();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.method;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.binding.convert.ConversionService;
|
||||
import org.springframework.binding.convert.support.DefaultConversionService;
|
||||
import org.springframework.core.style.StylerUtils;
|
||||
import org.springframework.util.CachingMapDecorator;
|
||||
|
||||
/**
|
||||
* A helper for invoking typed methods on abritrary objects, with support for
|
||||
* argument value type conversion from values retrieved from a argument
|
||||
* attribute source.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class MethodInvoker {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(MethodInvoker.class);
|
||||
|
||||
/**
|
||||
* Conversion service for converting arguments to the neccessary type if
|
||||
* required.
|
||||
*/
|
||||
private ConversionService conversionService = new DefaultConversionService();
|
||||
|
||||
/**
|
||||
* A cache of invoked bean methods, keyed weakly.
|
||||
*/
|
||||
private CachingMapDecorator methodCache = new CachingMapDecorator(true) {
|
||||
public Object create(Object key) {
|
||||
return ((MethodKey) key).getMethod();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the conversion service to convert argument values as needed.
|
||||
*/
|
||||
public void setConversionService(ConversionService conversionService) {
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke the method on the bean provided. Argument values are pulled from
|
||||
* the provided argument source.
|
||||
* @param signature the definition of the method to invoke, including the
|
||||
* method name and the method argument types
|
||||
* @param bean the bean to invoke
|
||||
* @param argumentSource the source for method arguments
|
||||
* @return the invoked method's return value
|
||||
* @throws MethodInvocationException the method could not be invoked
|
||||
*/
|
||||
public Object invoke(MethodSignature signature, Object bean, Object argumentSource)
|
||||
throws MethodInvocationException {
|
||||
Parameters parameters = signature.getParameters();
|
||||
Object[] arguments = new Object[parameters.size()];
|
||||
for (int i = 0; i < parameters.size(); i++) {
|
||||
Parameter parameter = parameters.getParameter(i);
|
||||
Object argument = parameter.evaluateArgument(argumentSource, null);
|
||||
arguments[i] = applyTypeConversion(argument, parameter.getType());
|
||||
}
|
||||
Class[] parameterTypes = parameters.getTypesArray();
|
||||
for (int i = 0; i < parameterTypes.length; i++) {
|
||||
if (parameterTypes[i] == null) {
|
||||
Object argument = arguments[i];
|
||||
if (argument != null) {
|
||||
parameterTypes[i] = argument.getClass();
|
||||
}
|
||||
}
|
||||
}
|
||||
MethodKey key = new MethodKey(bean.getClass(), signature.getMethodName(), parameterTypes);
|
||||
try {
|
||||
Method method = (Method) methodCache.get(key);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Invoking method with signature [" + key + "] with arguments "
|
||||
+ StylerUtils.style(arguments) + " on bean [" + bean + "]");
|
||||
|
||||
}
|
||||
Object returnValue = method.invoke(bean, arguments);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Invoked method with signature [" + key + "] returned value [" + returnValue + "]");
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new MethodInvocationException(signature, arguments, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply type conversion on the event parameter if neccessary
|
||||
*
|
||||
* @param parameterValue the raw argument value
|
||||
* @param targetType the target type for the matching method argument
|
||||
* @return the converted method argument
|
||||
*/
|
||||
protected Object applyTypeConversion(Object parameterValue, Class targetType) {
|
||||
if (parameterValue == null || targetType == null) {
|
||||
return parameterValue;
|
||||
}
|
||||
return conversionService.getConversionExecutor(parameterValue.getClass(), targetType).execute(parameterValue);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.method;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* A helper for resolving and caching a Java method by reflection.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class MethodKey implements Serializable {
|
||||
|
||||
/**
|
||||
* The class the method is a member of.
|
||||
*/
|
||||
private Class declaredType;
|
||||
|
||||
/**
|
||||
* The method name.
|
||||
*/
|
||||
private String methodName;
|
||||
|
||||
/**
|
||||
* The method's actual parameter types.
|
||||
*/
|
||||
private Class[] parameterTypes;
|
||||
|
||||
/**
|
||||
* A cached handle to the resolved method (may be null).
|
||||
*/
|
||||
private transient Method method;
|
||||
|
||||
/**
|
||||
* Create a new method key.
|
||||
* @param declaredType the class the method is a member of
|
||||
* @param methodName the method name
|
||||
* @param parameterTypes the method's parameter types, or <code>null</code>
|
||||
* if the method has no parameters
|
||||
*/
|
||||
public MethodKey(Class declaredType, String methodName, Class[] parameterTypes) {
|
||||
Assert.notNull(declaredType, "The method's declared type is required");
|
||||
Assert.notNull(methodName, "The method name is required");
|
||||
this.declaredType = declaredType;
|
||||
this.methodName = methodName;
|
||||
this.parameterTypes = parameterTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the class the method is a member of.
|
||||
*/
|
||||
public Class getDeclaredType() {
|
||||
return declaredType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the method name.
|
||||
*/
|
||||
public String getMethodName() {
|
||||
return methodName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the method parameter types.
|
||||
*/
|
||||
public Class[] getParameterTypes() {
|
||||
return parameterTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the keyed method, resolving it if necessary via reflection.
|
||||
*/
|
||||
public Method getMethod() throws InvalidMethodKeyException {
|
||||
if (method == null) {
|
||||
method = resolveMethod();
|
||||
}
|
||||
return method;
|
||||
}
|
||||
|
||||
// internal helpers
|
||||
|
||||
/**
|
||||
* Resolve the keyed method.
|
||||
*/
|
||||
protected Method resolveMethod() throws InvalidMethodKeyException {
|
||||
try {
|
||||
return declaredType.getMethod(methodName, getParameterTypes());
|
||||
}
|
||||
catch (NoSuchMethodException e) {
|
||||
Method method = findMethodConsiderAssignableParameterTypes();
|
||||
if (method != null) {
|
||||
return method;
|
||||
}
|
||||
else {
|
||||
throw new InvalidMethodKeyException(this, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the keyed method using 'relaxed' typing.
|
||||
*/
|
||||
protected Method findMethodConsiderAssignableParameterTypes() {
|
||||
Method[] candidateMethods = getDeclaredType().getMethods();
|
||||
for (int i = 0; i < candidateMethods.length; i++) {
|
||||
if (candidateMethods[i].getName().equals(methodName)) {
|
||||
// Check if the method has the correct number of parameters.
|
||||
Class[] candidateParameterTypes = candidateMethods[i].getParameterTypes();
|
||||
if (candidateParameterTypes.length == getParameterTypes().length) {
|
||||
int numberOfCorrectArguments = 0;
|
||||
for (int j = 0; j < candidateParameterTypes.length; j++) {
|
||||
// Check if the candidate type is assignable to the sig
|
||||
// parameter type.
|
||||
Class candidateType = candidateParameterTypes[j];
|
||||
Class parameterType = parameterTypes[j];
|
||||
if (parameterType != null) {
|
||||
if (isAssignable(candidateType, parameterType)) {
|
||||
numberOfCorrectArguments++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// just match on a null param type (effectively
|
||||
// 'any')
|
||||
numberOfCorrectArguments++;
|
||||
}
|
||||
}
|
||||
if (numberOfCorrectArguments == parameterTypes.length) {
|
||||
return candidateMethods[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof MethodKey)) {
|
||||
return false;
|
||||
}
|
||||
MethodKey other = (MethodKey) obj;
|
||||
return declaredType.equals(other.declaredType) && methodName.equals(other.methodName)
|
||||
&& parameterTypesEqual(other.parameterTypes);
|
||||
}
|
||||
|
||||
private boolean parameterTypesEqual(Class[] other) {
|
||||
if (parameterTypes == other) {
|
||||
return true;
|
||||
}
|
||||
if (parameterTypes.length != other.length) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < this.parameterTypes.length; i++) {
|
||||
if (!ObjectUtils.nullSafeEquals(parameterTypes[i], other[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return declaredType.hashCode() + methodName.hashCode() + parameterTypesHash();
|
||||
}
|
||||
|
||||
private int parameterTypesHash() {
|
||||
if (parameterTypes == null) {
|
||||
return 0;
|
||||
}
|
||||
int hash = 0;
|
||||
for (int i = 0; i < parameterTypes.length; i++) {
|
||||
Class parameterType = parameterTypes[i];
|
||||
if (parameterType != null) {
|
||||
hash += parameterTypes[i].hashCode();
|
||||
}
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
// internal helpers
|
||||
|
||||
/**
|
||||
* Determine if the given target type is assignable from the given value
|
||||
* type, assuming setting by reflection. Considers primitive wrapper classes
|
||||
* as assignable to the corresponding primitive types. <p> NOTE: Pulled from
|
||||
* ClassUtils in Spring 2.0 for 1.2.8 compatability. Should be collapsed
|
||||
* when 1.2.9 is released.
|
||||
* @param targetType the target type
|
||||
* @param valueType the value type that should be assigned to the target
|
||||
* type
|
||||
* @return if the target type is assignable from the value type
|
||||
*/
|
||||
private static boolean isAssignable(Class targetType, Class valueType) {
|
||||
return (targetType.isAssignableFrom(valueType) || targetType.equals(primitiveWrapperTypeMap.get(valueType)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Map with primitive wrapper type as key and corresponding primitive type
|
||||
* as value, for example: Integer.class -> int.class.
|
||||
*/
|
||||
private static final Map primitiveWrapperTypeMap = new HashMap(8);
|
||||
|
||||
static {
|
||||
primitiveWrapperTypeMap.put(Boolean.class, boolean.class);
|
||||
primitiveWrapperTypeMap.put(Byte.class, byte.class);
|
||||
primitiveWrapperTypeMap.put(Character.class, char.class);
|
||||
primitiveWrapperTypeMap.put(Double.class, double.class);
|
||||
primitiveWrapperTypeMap.put(Float.class, float.class);
|
||||
primitiveWrapperTypeMap.put(Integer.class, int.class);
|
||||
primitiveWrapperTypeMap.put(Long.class, long.class);
|
||||
primitiveWrapperTypeMap.put(Short.class, short.class);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return methodName + "(" + parameterTypesString() + ")";
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method that returns the parameter types describing the
|
||||
* signature of the method as a string.
|
||||
*/
|
||||
private String parameterTypesString() {
|
||||
StringBuffer parameterTypesString = new StringBuffer();
|
||||
for (int i = 0; i < parameterTypes.length; i++) {
|
||||
parameterTypesString.append(ClassUtils.getShortName(parameterTypes[i]));
|
||||
if (i < parameterTypes.length - 1) {
|
||||
parameterTypesString.append(',');
|
||||
}
|
||||
}
|
||||
return parameterTypesString.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.method;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A specification for a method consisting of the methodName and an optional set
|
||||
* of named arguments. This class provides the ability to resolve a method with
|
||||
* parameters and evaluate its argument values as part of a
|
||||
* {@link MethodInvoker method invoker attempt}.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class MethodSignature implements Serializable {
|
||||
|
||||
/**
|
||||
* The name of the method, e.g "execute".
|
||||
*/
|
||||
private String methodName;
|
||||
|
||||
/**
|
||||
* The parameter types of the method, e.g "int param1".
|
||||
*/
|
||||
private Parameters parameters;
|
||||
|
||||
/**
|
||||
* Creates a method signature with no parameters.
|
||||
* @param methodName the name of the method
|
||||
*/
|
||||
public MethodSignature(String methodName) {
|
||||
this(methodName, Parameters.NONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a method signature with a single parameter.
|
||||
* @param methodName the name of the method
|
||||
* @param parameter the method parameter
|
||||
*/
|
||||
public MethodSignature(String methodName, Parameter parameter) {
|
||||
this(methodName, new Parameters(parameter));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a method signature with a list of parameters.
|
||||
* @param methodName the name of the method
|
||||
* @param parameters the method parameters
|
||||
*/
|
||||
public MethodSignature(String methodName, Parameters parameters) {
|
||||
Assert.notNull(methodName, "The method name is required");
|
||||
Assert.notNull(parameters, "The parameters are required");
|
||||
this.methodName = methodName;
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the method name.
|
||||
*/
|
||||
public String getMethodName() {
|
||||
return methodName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the method parameters.
|
||||
*/
|
||||
public Parameters getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof MethodSignature)) {
|
||||
return false;
|
||||
}
|
||||
MethodSignature other = (MethodSignature) obj;
|
||||
return methodName.equals(methodName) && parameters.equals(other.parameters);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return methodName.hashCode() + parameters.hashCode();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return new ToStringCreator(this).append("methodName", methodName).append("parameters", parameters).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.method;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.binding.expression.EvaluationContext;
|
||||
import org.springframework.binding.expression.Expression;
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* A named method parameter. Each parameter has an identifying name and is of a
|
||||
* specified type (class).
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class Parameter implements Serializable {
|
||||
|
||||
/**
|
||||
* The class of the parameter, e.g "springbank.AccountNumber".
|
||||
*/
|
||||
private Class type;
|
||||
|
||||
/**
|
||||
* The name of the parameter as an evaluatable expression, e.g
|
||||
* "accountNumber".
|
||||
*/
|
||||
private Expression name;
|
||||
|
||||
/**
|
||||
* Create a new named parameter definition. Named parameters are capable of resolving
|
||||
* parameter values (arguments) from argument sources.
|
||||
* @param type the type the parameter type, may be null
|
||||
* @param name the name the method argument expression (required)
|
||||
*/
|
||||
public Parameter(Class type, Expression name) {
|
||||
Assert.notNull(name, "The parameter name expression is required");
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parameter type.
|
||||
*/
|
||||
public Class getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the method name.
|
||||
*/
|
||||
public Expression getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate this method parameter against the provided argument source,
|
||||
* returning a single method argument value.
|
||||
* @param argumentSource the meyhod argument source
|
||||
* @param context the evaluation context
|
||||
* @return the method argument value
|
||||
*/
|
||||
public Object evaluateArgument(Object argumentSource, EvaluationContext context) {
|
||||
return name.evaluate(argumentSource, context);
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof Parameter)) {
|
||||
return false;
|
||||
}
|
||||
Parameter other = (Parameter) obj;
|
||||
return ObjectUtils.nullSafeEquals(type, other.type) && name.equals(other.name);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return (type != null ? type.hashCode() : 0) + name.hashCode();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return new ToStringCreator(this).append("type", type).append("name", name).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.method;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An ordered list of method parameters.
|
||||
*
|
||||
* @author Keith
|
||||
*/
|
||||
public class Parameters implements Serializable {
|
||||
|
||||
/**
|
||||
* Canonical instance for an empty parameters list.
|
||||
*/
|
||||
public static final Parameters NONE = new Parameters(0);
|
||||
|
||||
/**
|
||||
* The list.
|
||||
*/
|
||||
private List parameters;
|
||||
|
||||
/**
|
||||
* Create a parameter list of the default size (3 elements).
|
||||
*/
|
||||
public Parameters() {
|
||||
this(3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a parameter list with the specified size.
|
||||
* @param size the size
|
||||
*/
|
||||
public Parameters(int size) {
|
||||
this.parameters = new ArrayList(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a parameter list with one parameter.
|
||||
* @param parameter the single parameter
|
||||
*/
|
||||
public Parameters(Parameter parameter) {
|
||||
this.parameters = new ArrayList(1);
|
||||
add(parameter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a parameter list from the parameter array.
|
||||
* @param parameters the parameters
|
||||
*/
|
||||
public Parameters(Parameter[] parameters) {
|
||||
this.parameters = new ArrayList(parameters.length);
|
||||
addAll(parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new parameter to this list.
|
||||
* @param parameter the parameter
|
||||
*/
|
||||
public boolean add(Parameter parameter) {
|
||||
return this.parameters.add(parameter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new parameters to this list.
|
||||
* @param parameters the parameters
|
||||
*/
|
||||
public boolean addAll(Parameter[] parameters) {
|
||||
return this.parameters.addAll(Arrays.asList(parameters));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a parameter iterator.
|
||||
* @return the iterator
|
||||
*/
|
||||
public Iterator iterator() {
|
||||
return parameters.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array containing each parameter type.
|
||||
* @return the types
|
||||
*/
|
||||
public Class[] getTypesArray() {
|
||||
int i = 0;
|
||||
Class[] types = new Class[parameters.size()];
|
||||
for (Iterator it = parameters.iterator(); it.hasNext();) {
|
||||
Parameter param = (Parameter)it.next();
|
||||
types[i] = param.getType();
|
||||
i++;
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of parameters in this list.
|
||||
* @return the size
|
||||
*/
|
||||
public int size() {
|
||||
return parameters.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the parameter at the provided index.
|
||||
* @param index the parameter index
|
||||
* @return the parameter at that index
|
||||
* @throws IndexOutOfBoundsException if the provided index is out of bounds
|
||||
*/
|
||||
public Parameter getParameter(int index) throws IndexOutOfBoundsException {
|
||||
return (Parameter)parameters.get(index);
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof Parameters)) {
|
||||
return false;
|
||||
}
|
||||
Parameters other = (Parameters)obj;
|
||||
return parameters.equals(other.parameters);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return parameters.hashCode();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return parameters.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.binding.method;
|
||||
|
||||
import org.springframework.binding.convert.ConversionContext;
|
||||
import org.springframework.binding.convert.ConversionException;
|
||||
import org.springframework.binding.convert.ConversionService;
|
||||
import org.springframework.binding.convert.support.ConversionServiceAwareConverter;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Converter that takes an encoded string representation and produces a
|
||||
* corresponding <code>MethodSignature</code> object.
|
||||
* <p>
|
||||
* This converter supports the following encoded forms:
|
||||
* <ul>
|
||||
* <li> "methodName" - the name of the method to invoke, where the method is
|
||||
* expected to have no arguments. </li>
|
||||
* <li> "methodName(param1Type param1Name, paramNType paramNName)" - the name of
|
||||
* the method to invoke, where the method is expected to have parameters
|
||||
* delimited by a comma. In this example, the method has two parameters. The
|
||||
* type is either the fully-qualified class of the argument OR a known type
|
||||
* alias. The name is the logical name of the argument, which is used during
|
||||
* data binding to retrieve the argument value. </li>
|
||||
* </ul>
|
||||
*
|
||||
* @see MethodSignature
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class TextToMethodSignature extends ConversionServiceAwareConverter {
|
||||
|
||||
/**
|
||||
* Create a new converter that converts strings to MethodSignature objects.
|
||||
*/
|
||||
public TextToMethodSignature() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new converter that converts strings to MethodSignature objects.
|
||||
* @param conversionService the conversion service to use
|
||||
*/
|
||||
public TextToMethodSignature(ConversionService conversionService) {
|
||||
super(conversionService);
|
||||
}
|
||||
|
||||
public Class[] getSourceClasses() {
|
||||
return new Class[] { String.class };
|
||||
}
|
||||
|
||||
public Class[] getTargetClasses() {
|
||||
return new Class[] { MethodSignature.class };
|
||||
}
|
||||
|
||||
protected Object doConvert(Object source, Class targetClass, ConversionContext context) throws Exception {
|
||||
String encodedMethodKey = (String)source;
|
||||
encodedMethodKey = encodedMethodKey.trim();
|
||||
int openParan = encodedMethodKey.indexOf('(');
|
||||
if (openParan == -1) {
|
||||
return new MethodSignature(encodedMethodKey);
|
||||
}
|
||||
else {
|
||||
String methodName = encodedMethodKey.substring(0, openParan);
|
||||
int closeParan = encodedMethodKey.lastIndexOf(')');
|
||||
if (closeParan == -1) {
|
||||
throw new ConversionException(encodedMethodKey, MethodSignature.class,
|
||||
"Syntax error: No close parenthesis specified for method parameter list", null);
|
||||
}
|
||||
String delimParamList = encodedMethodKey.substring(openParan + 1, closeParan);
|
||||
String[] paramArray = StringUtils.commaDelimitedListToStringArray(delimParamList);
|
||||
Parameters params = new Parameters(paramArray.length);
|
||||
for (int i = 0; i < paramArray.length; i++) {
|
||||
String param = paramArray[i].trim();
|
||||
String[] typeAndName = StringUtils.split(param, " ");
|
||||
if (typeAndName != null && typeAndName.length == 2) {
|
||||
Class type = (Class)converterFor(String.class, Class.class).execute(typeAndName[0]);
|
||||
params.add(new Parameter(type, parseExpression(typeAndName[1].trim())));
|
||||
}
|
||||
else {
|
||||
params.add(new Parameter(null, parseExpression(param)));
|
||||
}
|
||||
}
|
||||
return new MethodSignature(methodName, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<html>
|
||||
<body>
|
||||
<p>
|
||||
Method binding support for invoking abritrary methods on target beans.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user